2012-12-06 20 views
9

Một trong những chiến lược để tránh tình trạng bế tắc trong Java Đa luồng đang sử dụng hết thời gian chờ. Giả sử, một chuỗi đã có khóa trên một tài nguyên và hiện đang chờ khóa trên tài nguyên khác. Sau một khoảng thời gian nhất định nếu nó không thể có được khóa trên resource2 thì nó sẽ dừng chờ khóa trên resource2. Ngoài ra nó sẽ phát hành khóa trên resource1. Vì vậy, deadlocks sẽ được tránh.Sử dụng Timeout để tránh bế tắc trong đa luồng Java

Nhưng cách triển khai trong Java? Làm cách nào để "khóa" một cách rõ ràng? Cách xác định thời gian chờ để chờ khóa.

Lệnh và cú pháp java chính xác là gì. Bất kỳ ví dụ hello-worldish xin vui lòng?

+2

Các giải pháp khác; luôn luôn có được ổ khóa theo thứ tự như nhau, hoặc không bao giờ có được nhiều hơn một khóa. ;) –

+0

+1 cho 'Cách xác định thời gian chờ chờ khóa' – n611x007

Trả lời

8

Dưới đây là một ví dụ giả tạo với 2 ổ khóa và 2 chủ đề mà cố gắng để có được chúng trong thứ tự khác nhau. Nếu không có thời gian chờ, mã sẽ bế tắc.

public static void main(String[] args) throws Exception { 
    final ReentrantLock lock1 = new ReentrantLock(); 
    final ReentrantLock lock2 = new ReentrantLock(); 
    Runnable try1_2 = getRunnable(lock1, "lock 1", lock2, "lock 2"); 
    Runnable try2_1 = getRunnable(lock2, "lock 2", lock1, "lock 1"); 
    new Thread(try1_2).start(); 
    new Thread(try2_1).start(); 
} 

private static Runnable getRunnable(final ReentrantLock lock1, final String lock1Name, final ReentrantLock lock2, final String lock2Name) { 
    return new Runnable() { 
     @Override 
     public void run() { 
      try { 
       if (lock1.tryLock(1, TimeUnit.SECONDS)) { 
        System.out.println(lock1Name + " acquired in thread " + Thread.currentThread()); 
        if (lock2.tryLock(1, TimeUnit.SECONDS)) { 
         System.out.println(lock2Name + " acquired in thread " + Thread.currentThread()); 
         Thread.sleep(2000); 
        } else { 
         System.out.println("Could not acquire "+lock2Name + " in thread " + Thread.currentThread()); 
         lock1.unlock(); 
         System.out.println(lock1Name + " released in thread " + Thread.currentThread()); 
        } 
       } else { 
        System.out.println("Could not acquire " + lock1Name + " in thread " + Thread.currentThread()); 
       } 
      } catch (InterruptedException e) { 
       //you should not ignore it 
      } finally { 
       if (lock1.isHeldByCurrentThread()) lock1.unlock(); 
       if (lock2.isHeldByCurrentThread()) lock2.unlock(); 
      } 
     } 
    }; 
} 
+1

ví dụ từ Java Concurrency In Practice !! ;) –

+1

@assylias Khi gọi một phương thức được đồng bộ hóa của một đối tượng, luồng sẽ tự động tìm cách "khóa trên đối tượng đó". Trong khi sử dụng "java.util.concurrent.locks.Lock", chúng tôi sẽ không yêu cầu "khóa đối tượng mà đối tượng" có phương pháp mà chúng tôi đang gọi.Vì vậy, tôi nghĩ rằng, để sử dụng đúng cách "Khóa" lớp chúng ta KHÔNG nên đánh dấu phương pháp là đồng bộ. Nhưng chúng ta nên có một ví dụ của "Khóa" được hỗ trợ với đối tượng đó. Và trước khi gọi mã mà cần đồng bộ hóa, chúng ta nên dùng tryLock() trên khóa liên quan. ---- Plz tiếp tục đọc dưới đây bình luận ------ –

+0

@assylias Vì vậy, chúng tôi không thể chất khóa đối tượng có phương pháp chúng tôi đang gọi, nhưng hợp lý khóa. Giống như chúng tôi có một balckboard cho mỗi đối tượng và trước khi gọi phương pháp chúng tôi chỉ viết trên blackbord rằng "Này, tôi đã có khóa !!" . Chúng tôi không thực sự khóa đối tượng. Chủ đề khác sẽ kiểm tra bảng đen và thấy rằng một số đã "nói" rằng ông đã khóa. Vì vậy, nó sẽ không tiếp tục. Tôi có đúng không? –

3

Lock in Java

Use tryLock(timeout, timeunits); 

Dành được khóa nếu nó là miễn phí trong có thời gian chờ đợi và chủ đề hiện tại chưa được gián đoạn. Nếu khóa có sẵn, phương thức trả lại ngay lập tức với giá trị true.

Nếu khóa là không sẵn sau đó xử lí hiện tại trở nên tàn tật cho chủ đề mục đích lập kế hoạch và nằm im cho đến khi một trong ba điều xảy ra:

Các khóa được mua bởi thread hiện hành;

hoặc một số chủ đề khác ngắt chuỗi hiện tại và gián đoạn thu nhận khóa là được hỗ trợ;

hay The quy định thời gian chờ đợi trôi qua

3

có thể trợ giúp này,

Lock lock = null; 
lock=....; 
if (lock.tryLock(15L, TimeUnit.SECONDS)) { 
    try { 
     ........ 
    } finally { 
     lock.unlock(); 
    } 
} else { 
     // do sumthing 
} 
0

Trong Java 8+ Concurrency API bạn có thể thiết lập một thời gian rõ ràng cho một lock đợi khi nó điều kiện được thiết lập:

private Lock lock = new ReentrantLock(); 
private Condition myCondition = lock.newCondition(); 

try{    
    myCondition.await(1200L, TimeUnit.MILLISECONDS); 
} catch (InterruptedException e) { 
    System.out.println((e); 
} finally{ 
    lock.unlock(); 
} 

Các khóa sẽ đợi cho đến khi nó nhận được một signal() hoặc signalAll() từ thread khác hoặc cho đến khi thời gian 1,2 giây hết hạn.

Các vấn đề liên quan