2010-06-17 34 views
5

Tôi đang gặp khó khăn với quyết định. Tôi đang viết một thư viện/API an toàn. Người nghe có thể được đăng ký, vì vậy khách hàng được thông báo khi có điều gì đó thú vị xảy ra. Triển khai nào trong hai triển khai phổ biến nhất?thông báo cho người nghe bên trong hoặc bên ngoài đồng bộ hóa bên trong

class MyModule { 
    protected Listener listener; 

    protected void somethingHappens() { 
     synchronized(this) { 
      ... do useful stuff ... 
      listener.notify(); 
     } 
    } 
} 

hoặc

class MyModule { 
    protected Listener listener; 

    protected void somethingHappens() { 
     Listener l = null; 

     synchronized(this) { 
      ... do useful stuff ... 
      l = listener; 
     } 
     l.notify(); 
    } 
} 

Trong việc thực hiện đầu tiên, người nghe được thông báo bên trong đồng bộ hóa. Trong lần thực hiện thứ hai, điều này được thực hiện bên ngoài đồng bộ hóa.

Tôi cảm thấy rằng điều thứ hai được thông báo, vì nó làm cho ít chỗ hơn cho deadlocks tiềm năng. Nhưng tôi đang gặp rắc rối để thuyết phục bản thân mình.

Nhược điểm của lần thứ hai là khách hàng có thể nhận được thông báo 'không chính xác', điều này xảy ra nếu nó truy cập và thay đổi mô-đun trước câu lệnh l.notify(). Ví dụ, nếu nó yêu cầu các mô-đun để ngừng gửi thông báo, notificaiton này được gửi đi anyway. Đây không phải là trường hợp trong lần thực hiện đầu tiên.

thanks a lot

Trả lời

1

Nó phụ thuộc vào nơi bạn đang nhận được người nghe trong phương pháp của bạn, có bao nhiêu người nghe bạn có, làm thế nào người nghe đặt mua/unsubscribes

Giả sử từ ví dụ của bạn, bạn chỉ có một người biết lắng nghe rồi bạn có thể tốt hơn để sử dụng các phần quan trọng (hoặc màn hình) cho các phần khác nhau của lớp thay vì khóa toàn bộ đối tượng.

Bạn có thể có một khóa để thực hiện các tác vụ trong phương thức cụ thể cho đối tượng/nhiệm vụ hiện tại và một cho người nghe đăng ký/hủy đăng ký/thông báo (để đảm bảo rằng người nghe không thay đổi trong khi thông báo).

Tôi cũng sẽ sử dụng một ReadWriteLock bảo vệ bạn tham khảo người nghe (hoặc đơn hoặc danh sách các thính)

trả lời bạn nhận xét:

Tôi nghĩ rằng bạn nên thông báo cho người nghe sau khi bạn có mở khóa lớp. Điều này là do kết quả của thông báo đó có thể dẫn đến một luồng khác nhau cố gắng truy cập vào lớp, mà nó có thể không thực hiện được, trong một số trường hợp nhất định, dẫn đến bế tắc.

Thông báo cho người nghe (nếu được bảo vệ như tôi đã mô tả) không nên giữ bất kỳ chủ đề nào khác yêu cầu cơ sở vật chất của lớp học. Chiến lược tốt nhất là tạo ổ khóa dành riêng cho trạng thái của lớp và khóa cụ thể cho thông báo an toàn.

Nếu bạn lấy ví dụ về thông báo treo, điều này có thể được khóa bằng cách điều chỉnh thông báo, vì vậy nếu một thông báo 'treo' khác, việc tạm ngừng sẽ được xử lý hoặc thông báo hiện tại hoàn tất, nếu chuỗi khác đình chỉ thông báo giữa nhiệm vụ đang được xử lý và thông báo xảy ra, l.notify() sẽ không xảy ra.

Listener l = null; 

synchronised(processLock_) { 
    ... do stuff.... 
    synchronised(notifyLock_) { 
     l = listener; 
    } 
} 
// 
// current thread preempted by other thread that suspends notification here. 
// 

synchronised(notifyLock_) { // ideally use a readwritelock here... 
    l = allowNotify_ ? l: null; 
} 
if(l) 
    l.notify(); 
+0

Cảm ơn câu trả lời của bạn. Tôi cố ý chấm không đề cập đến phần đăng ký/hủy đăng ký. Tôi muốn giả sử có một người nghe cố định. Câu hỏi của tôi là khá khôn ngoan nếu phơi bày sự đồng bộ hóa bên ngoài lớp học hay không. –

+0

@Jary Zeels, xem phần bổ sung để trả lời –

+0

Cảm ơn Adrian đã làm rõ, tôi hiểu ngay bây giờ. Tình huống với một người nghe rõ ràng với tôi. Tôi sẽ suy nghĩ về tình huống khi nhiều người nghe có thể được đăng ký, bởi vì sau đó, tái entrancycan là một vấn đề. Bạn không muốn các sự kiện được phân phối theo thứ tự sai khi ví dụ một trong những người nghe được thông báo thực hiện điều gì đó kích hoạt một thông báo mới. Tôi sẽ suy nghĩ về nó và quay trở lại với nhiều câu hỏi hơn nếu cần thiết. Cảm ơn một lần nữa. –

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