2011-12-08 32 views
7

Như đã đề cập trong một số câu trả lời cho câu hỏi này:Hiện một ReadWriteLock làm cho từ khóa đồng bộ không cần thiết?

What is the name of this locking technique?

Tôi thực hiện một ReentrantReadWriteLock và nhìn thấy sự tăng tốc rất lớn (Tôi biết có một số tranh chấp khóa trong một lớp học của tôi và sử dụng một khóa reentrant đã làm những điều giúp tốc độ lên).

Nhưng bây giờ tôi tự hỏi: nếu bên trong một lớp tất cả truy cập (cả đọc và viết) được thực hiện bằng cách khóa đầu tiên hoặc khóa đọc hoặc khóa ghi, có nghĩa là từ khóa được đồng bộ hóa được sử dụng nữa trong lớp đó?

Ví dụ, đây là một quan chức Java 1.6 dụ tìm thấy tại http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html

class RWDictionary { 
    private final Map<String, Data> m = new TreeMap<String, Data>(); 
    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); 
    private final Lock r = rwl.readLock(); 
    private final Lock w = rwl.writeLock(); 

    public Data get(String key) { 
     r.lock(); 
     try { return m.get(key); } 
     finally { r.unlock(); } 
    } 
    public String[] allKeys() { 
     r.lock(); 
     try { return m.keySet().toArray(); } 
     finally { r.unlock(); } 
    } 
    public Data put(String key, Data value) { 
     w.lock(); 
     try { return m.put(key, value); } 
     finally { w.unlock(); } 
    } 
    public void clear() { 
     w.lock(); 
     try { m.clear(); } 
     finally { w.unlock(); } 
    } 
} 

Không có synchronize từ khóa.

Bây giờ tôi nhận ra rằng một trong những điểm khóa như vậy là nhanh hơn các phương pháp khác (trong trường hợp này nhanh hơn đồng bộ hóa) nhưng giải thích kỹ thuật đằng sau điều này là gì?

Việc sử dụng khóa ghi đọc trong lớp trong mọi phương thức lấy/cập nhật "thay thế" đồng bộ hóa từ khóa cho các phương pháp này không?

+0

Tôi giả sử bạn đã đồng bộ hóa trên cá thể, như 'đồng bộ hóa (điều này)'. Thay vào đó, nếu bạn đã đồng bộ hóa trên hai đối tượng khác nhau, một cho đọc và một cho viết, bạn sẽ đạt được hiệu suất tương tự. Với 'this' sync, khi' put' đang được xử lý, không cần thiết 'get' cũng được thực hiện để chờ đợi. Với các đối tượng khóa khác nhau, tranh chấp này biến mất. – srkavin

+0

Đối với hầu hết việc triển khai bản đồ, nó * là * cần thiết để thực hiện chờ trong khi đang thực hiện. – Affe

+0

@srkavin Cuộc tranh luận sẽ biến mất, nhưng khả năng hiển thị bộ nhớ sẽ đảm bảo. 'Get' của bạn có thể đã thấy một cập nhật một phần từ' put', vì chúng không được đồng bộ hóa với nhau. – yshavit

Trả lời

10

Nếu bạn đọc javadocs trên ReadWriteLock, và Lock, họ đặc biệt nói rằng Locks phải cung cấp ngữ nghĩa bộ nhớ giống như synchronized keyword:

Tất cả Khóa triển khai phải thực thi các ngữ nghĩa đồng bộ hóa bộ nhớ tương tự như được cung cấp bởi được xây dựng trong khóa màn hình, như mô tả trong Java Language Specification, Third Edition (17,4 Memory Model):

(. Đó là từ javadoc Khóa; các ReadWriteLock đề cập đến Khóa để mô tả ngữ nghĩa của nó)

Vì vậy, có, nó thay thế từ khóa synchronized. Trong thực tế, bạn có thể thay thế mọi khối synchronized trong mã của bạn bằng Khóa và có cùng ngữ nghĩa (và, tùy thuộc vào jvm, thậm chí có thể tăng hiệu suất nhỏ). Nhưng bạn sẽ giao dịch một chút tốc độ cho độ chi tiết hơn và nếu bạn quên mở khóa một trong những khóa đó, bạn có thể bế tắc chương trình của mình.

gì quyền hạn rất nhiều trong số này là các thuật toán nonblocking (compare-and-swap là trung tâm của họ) kết hợp với ngữ nghĩa bộ nhớ của volatile lĩnh vực, trong đó quy định rằng nếu bạn viết thư cho một lĩnh vực volatile, bất kỳ chủ đề mà sau đó đọc lĩnh vực mà đã thấy ít nhất cùng một trạng thái của thế giới như bạn đã thấy khi bạn viết nó. (Họ cũng có thể thấy một số hoặc tất cả những gì đã xảy ra sau khi viết.) Những công cụ này có thể làm cho một số mã khá nhanh, nhưng chúng cũng tinh tế và dễ bị sai - hầu như luôn luôn tốt nhất để ở lại với cấp cao hơn các cấu trúc (chẳng hạn như ReadWriteLock bạn đang sử dụng).

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