Java Multi-Threading Gone اشتباه: یک کابوس پس زمینه واقعی در دنیای واقعی

شما به تازگی برنامه بوت بهار با کارایی بالا را مستقر کرده اید. تا زمانی که سنبله های ترافیکی را انجام می دهد ، هموار اجرا می شود. ناگهان ، همه چیز یخبشر بدون خطا ، بدون تصادف ، فقط یک سیستم ساکت و بی پاسخ.
خوش آمدید بن بست جهنم– جایی که دو موضوع منابع را گروگان می گیرند و از عقب نشینی امتناع می ورزند.
چگونه همه چیز اشتباه شد
باطن شما دارای دو کار پس زمینه است که منابع مشترک را به روز می کنند:
- یک موضوع معاملات پایگاه داده را مدیریت می کند.
- برای سرعت بخشیدن به پاسخ ها ، حافظه مخفی را انجام می دهد.
به نظر می رسد مانند یک معماری محکم ، درست است؟ اما در یک سناریوی با کنفرانس بالا ، این موضوعات در نهایت منتظر یکدیگر می شوند و یک بن بست غیرقابل تحمل ایجاد می کنند.
کد مشکل ساز:
class Resource {
private final String name;
public Resource(String name) { this.name = name; }
public String getName() { return name; }
}
class DeadlockExample {
private final Resource resource1 = new Resource("Database Connection");
private final Resource resource2 = new Resource("Cache Layer");
public void processA() {
synchronized (resource1) {
System.out.println(Thread.currentThread().getName() + " locked " + resource1.getName());
try { Thread.sleep(100); } catch (InterruptedException ignored) {}
synchronized (resource2) {
System.out.println(Thread.currentThread().getName() + " locked " + resource2.getName());
}
}
}
public void processB() {
synchronized (resource2) {
System.out.println(Thread.currentThread().getName() + " locked " + resource2.getName());
try { Thread.sleep(100); } catch (InterruptedException ignored) {}
synchronized (resource1) {
System.out.println(Thread.currentThread().getName() + " locked " + resource1.getName());
}
}
}
}
public class DeadlockSimulator {
public static void main(String[] args) {
DeadlockExample system = new DeadlockExample();
Thread t1 = new Thread(system::processA, "Thread-A");
Thread t2 = new Thread(system::processB, "Thread-B");
t1.start();
t2.start();
}
}
چرا پس زمینه شما یخ زد
-
Thread-A
قفل می کند اتصال پایگاه داده و منتظر لایه حافظهبشر -
Thread-B
قفل می کند لایه حافظه و منتظر اتصال پایگاه دادهبشر - هیچ یک از موضوع نمی توانند ادامه دهند.
- پس زمینه شما متوقف می شود تا متوقف شودبشر
رفع: قفل دقیق تر
گزینه 1: سفارش قفل مداوم
همیشه قفل ها را به همان ترتیب در تمام موضوعات بدست آورید.
public void safeProcess() {
synchronized (resource1) { // Always lock DB first
System.out.println(Thread.currentThread().getName() + " locked " + resource1.getName());
try { Thread.sleep(100); } catch (InterruptedException ignored) {}
synchronized (resource2) { // Then lock Cache
System.out.println(Thread.currentThread().getName() + " locked " + resource2.getName());
}
}
}
اکنون ، مهم نیست که چند موضوع تخم ریزی کنید ، آنها نمی گواند در انتظار یکدیگر گیر کنید.
گزینه 2: استفاده کنید tryLock()
برای جلوگیری از بن بست
به جای انتظار نامحدود ، استفاده کنید ReentrantLock.tryLock()
بنابراین اگر یک منبع در دسترس نباشد ، یک موضوع می تواند حرکت کند.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class SafeResource {
private final Lock lock = new ReentrantLock();
public boolean tryLock() {
return lock.tryLock();
}
public void unlock() {
lock.unlock();
}
}
حال ، اگر یک نخ نمی توان قفل کرد، آن پشت سر گذاشتن به جای یخ زدن سیستم خود.
افکار نهایی: Taming Multi-Threading
چند رشته ای قدرتمند است ، اما بدون برخورد دقیق ، مانند بازی با Dynamite است. از بن بست توسط: همیشه قفل کردن منابع به همان ترتیب
استفاده
tryLock()
برای جلوگیری از انتظار نامحدود
نظارت بر فعالیت موضوع با ابزارها
دفعه بعد قفل کردن، شما دقیقاً می دانید کجا باید نگاه کنید.