مهدی عادلی فر
بنیانگذار توسینسو و برنامه نویس

چگونه از Deadlock در جاوا جلوگیری کنیم؟ آموزش پیشگیری از بن بست

چگونه جلوی بن بست در جاوا را بگیریم ؟ در زبان جاوا و بسیاری از زبان های سیستمی ممکن است حالاتی پیش بیاید که ادامه روند اجرای برنامه ممکن نباشد. این حالت زمانی اتفاق می افتد که چند thread یا برنامه در یک زمان منتظر یک منبع خاص باشند. به این حالت که همه ی برنامه ها در حال انتظار برای دیگری است deadlock یا بن بست می گویند. بن بست می تواند دلایل مختلفی داشته باشد. راه درستی برای جلوگیری از بن بست وجود ندارد.

دوره های شبکه، برنامه نویسی، مجازی سازی، امنیت، نفوذ و ... با برترین های ایران

به طور معمول بن بست زمانی اتفاق می افتد که یک شئ سنکرون شده (synchronized) منتظر قفل کردن منبعی است که توسط یک شی synchronized دیگر قفل شده است.سعی کنید برنامه زیر را اجرا کنید. این برنامه یک بن بست را نشان می دهد. در این برنامه به این دلیل بن بست رخ می دهد که هردوی threadها منتظر گرفتن منابعی است که توسط thread های دیگر گرفته شده است. هردوی آنها منتظر خواهند بود و رها نخواهند شد.

public class DeadlockDemo {
   public static Object addLock = new Object();
   public static Object subLock = new Object();

   public static void main(String args[]) {

      MyAdditionThread add = new MyAdditionThread();
      MySubtractionThread sub = new MySubtractionThread();
      add.start();
      sub.start();
   }
private static class MyAdditionThread extends Thread {
      public void run() {
         synchronized (addLock) {
        int a = 10, b = 3;
        int c = a + b;
            System.out.println("ترد جمع کردن: " + c);
            System.out.println("گرفتن قفل اول...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("ترد جمع کردن:در حال انتظار...");
            synchronized (subLock) {
               System.out.println("تردها: قفلها گرفته شده اند و انتظار...");
            }
         }
      }
   }
   private static class MySubtractionThread extends Thread {
      public void run() {
         synchronized (subLock) {
        int a = 10, b = 3;
        int c = a - b;
            System.out.println("ترد تفریق کردن: " + c);
            System.out.println("در حال گرفتن قفل...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("ترد تفریق کردن: در حال انتظار برای قفل...");
            synchronized (addLock) {
               System.out.println("تردها: قفلها گرفته شده اند و انتظار...");
            }
         }
      }
   }
}

خروجی کد بالا به شکل زیر خواهد بود

ترد جمع کردن: 13
ترد تفریق کردن: 7
گرفتن قفل اول  ...
گرفتن قفل دوم...
ترد جمع کردن:در حال انتظار...
تردها: قفلها گرفته شده اند و انتظار...

حال اگر در برنامه بالا ترتیب فراخوانی thread ها عوض شود مشکل بن بست حل می شود. به برنامه زیر دقت کنید:

public class DeadlockSolutionDemo {
   public static Object addLock = new Object();
   public static Object subLock = new Object();
 
   public static void main(String args[]) {
 
      MyAdditionThread add = new MyAdditionThread();
      MySubtractionThread sub = new MySubtractionThread();
      add.start();
      sub.start();
   }
 
 
private static class MyAdditionThread extends Thread {
      public void run() {
         synchronized (addLock) {
        int a = 10, b = 3;
        int c = a + b;
            System.out.println("ترد جمع کردن: " + c);
            System.out.println("گرفتن قفل اول...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("ترد جمع کردن: انتظار برای قفل...");
            synchronized (subLock) {
               System.out.println("تردها: نگه داشتن قفل های جمع و تفریق...");
            }
         }
      }
   }
    
   private static class MySubtractionThread extends Thread {
      public void run() {
         synchronized (addLock) {
        int a = 10, b = 3;
        int c = a - b;
            System.out.println("ترد تفریق کردن: " + c);
            System.out.println("گرفتن قفل دوم...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("ترد جمع کردن: انتظار برای قفل...");
            synchronized (subLock) {
               System.out.println("تردها: نگه داشتن قفل های جمع و تفریق...");
            }
         }
      }
   }
}

خروجی کد بالا به شکل زیر خواهد بود.

ترد جمع کردن: 13
گرفتن قفل اول...
ترد جمع کردن: در حال انتظار برای قفل...
تردها: نگه داشتن قفل های جمع و تفریق... ...
ترد تفریق: 7
گرفتن قفل دوم...
ترد تفریق کردن: در حال انتظار برای قفل...
تردها: نگه داشتن قفل های جمع و تفریق......

Itpro باشید

نویسنده: مهدی عادلی فر

منبع: انجمن تخصصی فناوری اطلاعات ایران

هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.


مهدی عادلی فر
مهدی عادلی فر

بنیانگذار توسینسو و برنامه نویس

مهدی عادلی، بنیان گذار TOSINSO. کارشناس ارشد نرم افزار کامپیوتر از دانشگاه صنعتی امیرکبیر و #C و جاوا و اندروید کار می کنم. در زمینه های موبایل و وب و ویندوز فعالیت دارم و به طراحی نرم افزار و اصول مهندسی نرم افزار علاقه مندم.

نظرات