2012-04-29 35 views
17

Tôi có hai phương pháp read()write() như bên dưới trong một lớp học.đồng bộ hóa phương pháp java và đọc/ghi loại trừ lẫn nhau

class Store 
{ 

    public void write() 
    { 
    // write to store; 
    } 

    public string read() 
    { 
    // read from store; 
    } 
} 

1) Đối tượng Store là một đơn.

2) Tôi có một lớp học Writer sẽ ghi vào cửa hàng và một số lớp học Reader sẽ đọc từ cửa hàng cùng một lúc.

Yêu cầu của tôi là khi người viết viết thư cho cửa hàng, tất cả người đọc phải đợi. tức là, khi kiểm soát trong write(), tất cả các cuộc gọi đến read() sẽ bị chặn. Làm thế nào để đạt được điều này? Tôi đã thử synchronize(Store.class) trong phương thức write(), nhưng dường như không hoạt động đối với tôi.

+0

bạn không muốn đồng bộ hóa trên đối tượng lớp ('được đồng bộ hóa (foo.class)') mà thay vào trường hợp bạn đang hoạt động. – andersoj

Trả lời

33

Tùy chọn tốt nhất trong trường hợp này là sử dụng khóa trình đọc ghi: ReadWriteLock. Nó cho phép một nhà văn duy nhất, nhưng nhiều độc giả đồng thời, do đó, nó là cơ chế hiệu quả nhất cho loại kịch bản này.

Một số mẫu mã:

class Store 
{ 
    private ReadWriteLock rwlock = new ReentrantReadWriteLock(); 

    public void write() 
    { 
     rwlock.writeLock().lock(); 
     try { 
      write to store; 
     } finally { 
      rwlock.writeLock().unlock(); 
     } 
    } 

    public String read() 
    { 
     rwlock.readLock().lock(); 
     try { 
      read from store; 
     } finally { 
      rwlock.readLock().unlock(); 
     } 
    } 
} 
+0

ReadWriteLock là một giao diện. ;) –

+0

@Peter Lawrey: Xin lỗi về điều đó. Đã sửa. :) – Tudor

+4

@Tudor bạn nên luôn luôn bọc _read của bạn để store_ và _write để store_ hoạt động trong một khối _try_ và chắc chắn để có 'mở khóa()' phương pháp trong một khối _finally_ tương ứng để ngăn chặn các khóa vẫn bị khóa nếu một ngoại lệ xảy ra . – matsev

0

Sử dụng một ReadWriteLock từ gói java.util.concurrent

3

synchronized sự là giải pháp đơn giản nhất vì vậy bạn nên giải thích những gì bạn có ý nghĩa bởi "không có vẻ như làm việc cho tôi "và có thể chỉ cho chúng tôi cách bạn sử dụng nó.

Giải pháp tốt hơn là sử dụng ReentrantReadWriteLock vì nó cho phép truy cập đồng thời vào người đọc.

2

Khi phương thức được đồng bộ hóa trên một đối tượng, một chuỗi thực hiện phương pháp này sẽ chặn tất cả các chuỗi khác cố gắng nhập một khối/phương pháp được đồng bộ hóa trên cùng một đối tượng.

Vì vậy, nếu bạn muốn các luồng của người viết cấm đọc bất kỳ chuỗi trình đọc nào, bạn phải đồng bộ hóa cả phương thức ghi và phương thức đọc. Không có lý do gì để đồng bộ hóa trên lớp Store. Đồng bộ hóa trên đối tượng Store là tự nhiên hơn:

public synchronized void write() { 
    write to store; 
} 

public synchronized String read() { 
    read from store; 
} 

Điều này, tuy nhiên, có thể có nhược điểm: nó cũng cấm đọc hai luồng đọc cùng một lúc. Nếu bạn thực sự cần điều này xảy ra, bạn nên sử dụng ReadWriteLock. Nhưng điều này sẽ dẫn đến mã ít hiệu quả hơn và khó hiểu hơn và duy trì. Tôi sẽ chỉ sử dụng nó nếu tôi đã đo lường rằng điều này là cần thiết.

+0

Tại sao bạn nói rằng 'ReadWriteLock' ít hoạt động hơn' đồng bộ'? Không có lý do kỹ thuật tốt nào cho điều đó vì cả hai phương pháp chỉ nên là một giao diện cấp cao hơn để điều khiển trực tiếp semaphore. – meustrus

+0

Trong thực tế, có vẻ như 'ReentrantReadWriteLock' thực sự có thể thực hiện * tốt hơn * so với 'đồng bộ', miễn là bạn không sử dụng khóa" công bằng ". Điều đó có vẻ là một kết luận của [so sánh IBM này giữa 'đồng bộ hóa 'và' ReentrantLock'] (http://www.ibm.com/developerworks/java/library/j-jtp10264/). Mặc dù nó không có giá trị gì mà 'ReentrantLock' không giống với' ReentrantReadWriteLock', tại sao bạn sẽ khóa độc giả nếu bạn không phải làm vậy? – meustrus

+0

Vấn đề với cách tiếp cận này là người đọc không thể đọc đồng thời cơ sở dữ liệu, trong khi trong nhiều trường hợp, đây không phải là vấn đề gì cả ... –

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