2012-09-25 19 views
23

Các mã sau đây được lấy từ JavaDoc of Condition:chờ vào một điều kiện trong một reentrant khóa

class BoundedBuffer { 
    final Lock lock = new ReentrantLock(); 
    final Condition notFull = lock.newCondition(); 
    final Condition notEmpty = lock.newCondition(); 

    final Object[] items = new Object[100]; 
    int putptr, takeptr, count; 

    public void put(Object x) throws InterruptedException { 
    lock.lock(); 
    try { 
     while (count == items.length) 
     notFull.await(); 
     items[putptr] = x; 
     if (++putptr == items.length) putptr = 0; 
     ++count; 
     notEmpty.signal(); 
    } finally { 
     lock.unlock(); 
    } 
    } 

    public Object take() throws InterruptedException { 
    lock.lock(); 
    try { 
     while (count == 0) 
     notEmpty.await(); 
     Object x = items[takeptr]; 
     if (++takeptr == items.length) takeptr = 0; 
     --count; 
     notFull.signal(); 
     return x; 
    } finally { 
     lock.unlock(); 
    } 
    } 
} 

Imagine 2 chủ đề, ConsumerNhà sản xuất, một sử dụng take, một put trên một trường hợp duy nhất của BoundedBuffer.

Hãy nói rằng Consumer đi đầu tiên, chạy take() trong đó ông khóa lock và bây giờ vòng trên notEmpty.await();.

Làm thế nào có thể bây giờ Nhà sản xuất có thể nhận được vào put() phương pháp qua khóa lock, mà đã được tổ chức bởi các Consumer?

Tôi thiếu gì ở đây? Là lock "tạm thời được phát hành" trong khi luồng đang chờ một trong các điều kiện của nó? Và chính xác reentrancy của khóa có nghĩa là gì?

+2

tôi là khoảng hai hỏi chính xác cùng một câu hỏi với chính xác cùng một ví dụ về JavaDoc :) Lưu tôi khỏi mất thời gian. – Bren

Trả lời

23

Cả hai Locksynchronized cho phép chủ đề bỏ khóa khi chờ và một chủ đề khác có thể lấy khóa. Để ngừng chờ, một luồng phải lấy lại khóa.

Lưu ý: Chúng không phát hành đầy đủ và nếu bạn theo dõi ngăn xếp, bạn có thể có nhiều chuỗi có vẻ như đang giữ khóa cùng lúc, nhưng hầu hết một trong số đó sẽ chạy (phần còn lại sẽ chặn)

Từ Condition.await()

các khóa liên quan đến tình trạng này là nguyên tử phát hành và xử lí hiện tại trở nên tàn tật cho các mục đích đề lập kế hoạch và nằm im cho đến khi một trong bốn điều sẽ xảy ra:

  • Một số luồng khác gọi phương thức signal() cho Điều kiện này và luồng hiện tại sẽ được chọn làm luồng được đánh thức; hoặc
  • Một số luồng khác gọi phương thức signalAll() cho Điều kiện này; hoặc
  • Một số chủ đề khác làm gián đoạn luồng hiện tại và việc gián đoạn việc tạm dừng luồng được hỗ trợ; hoặc
  • Một "đánh thức giả mạo" xảy ra.

Trong mọi trường hợp, trước khi phương pháp này có thể trả về luồng hiện tại phải lấy lại khóa được liên kết với điều kiện này. Khi chuỗi trả lại, chuỗi được đảm bảo giữ khóa này

+0

Bạn có thể cung cấp liên kết đến tài liệu liên quan không? – vektor

+1

@PeterLawrey '(phần còn lại sẽ đợi)' hoặc chặn? Tôi nghĩ rằng họ nên ở trong trạng thái khối'? – UnKnown

+0

Bạn có thể giải thích câu này: "Cả Khóa và đồng bộ tạm thời cho phép người khác lấy khóa khi họ đang chờ." Nó không có ý nghĩa với tôi. – Chin

5

Theo như thừa lại, điều này có nghĩa là một sợi có khóa nhất định có thể lấy lại cùng một khóa lần nữa. Nếu không như vậy, phương thức synchronized sẽ không thể gọi phương thức synchronized khác của cùng một đối tượng.

Tái uỷ thác không liên quan đến sự hiểu biết về vấn đề của bạn.

+0

Chính xác. Đôi khi thuật ngữ "khóa đệ quy" được sử dụng cho khóa reentrant, xem [Wikipedia] (https://en.wikipedia.org/wiki/Reentrant_mutex). – TheOperator

-2

Tôi đã thử nghiệm bên dưới mã với màn hình duy nhất và dưới luôn thực hiện tốt hơn - Thử nghiệm trên 2 máy lõi, hiệu suất Điều kiện là 10-15% so với mức trên trung bình

final Object sync = new Object(); 
    AtomicInteger add=new AtomicInteger(); 
    AtomicInteger remove=new AtomicInteger(); 
    final Object[] items = new Object[1]; 
    int putptr, takeptr, count;   

public void add(Object x) throws InterruptedException { 
     add.incrementAndGet(); 

    synchronized (sync) { 

     while (count == items.length) 
     sync.wait(); 
     items[putptr] = x; 
     if (++putptr == items.length) putptr = 0; 
     ++count; 
     sync.notify(); 
     } 
    } 

    public Object remove() throws InterruptedException { 
     remove.incrementAndGet(); 

    synchronized (sync) { 

     while (count == 0) 
     sync.wait(); 
     Object x = items[takeptr]; 
     if (++takeptr == items.length) takeptr = 0; 
     --count; 
     sync.notify(); 
     return x; 

     } 
    } 


    public static void main(String[] args) { 
    final BoundedBuffer bf=new BoundedBuffer(); 

    Thread put =new Thread(){ 
     public void run(){ 
     try { 
      while(true) 
      bf.add(new Object()); 
     } catch (InterruptedException e) { 

     } 
     } 

    }; 
    put.start(); 

    Thread take= new Thread(){ 
     public void run(){ 
     try { 
     while(true) 
      bf.remove(); 
     } catch (InterruptedException e) { 

     } 
     } 

    }; 
    take.start(); 

    try { 
     Thread.sleep(1000L); 
     put.interrupt(); 
     take.interrupt(); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 


    System.out.println("add:"+bf.add); 
    System.out.println("remove:"+bf.remove); 
Các vấn đề liên quan