2011-11-19 24 views
8

Tôi đang có một ứng dụng đa luồng bằng cách sử dụng một lớp tĩnh đơn cung cấp một danh sách. Tôi muốn getters của lớp tĩnh để làm việc một cách tự do (không được đồng bộ với nhau) nhưng khi một setter đang làm việc, tôi muốn tất cả các getters bị khóa và đợi cho đến khi công việc của setter được thực hiện. Tôi không muốn khóa getters khi chúng được gọi với nhau vì nó sẽ làm giảm hiệu suất rất nhiều. Getters được gọi là 1.000.000 lần mỗi ngày và setter chỉ có nghĩa vụ phải làm việc một lần mỗi ngày.Làm thế nào tôi có thể đồng bộ hóa getter trong khi một setter đang làm việc trong Java

+0

biến trạng thái? – Kris

Trả lời

8

Xem xét sử dụng một thực hiện java.util.concurrent.locks.ReadWriteLock, chẳng hạn như ReentrantReadWriteLock (xem javadoc)

Một ReadWriteLock duy trì một cặp khóa có liên quan, một cho read-only hoạt động và một cho văn bản. Khóa đọc có thể được giữ đồng thời bởi nhiều luồng đọc, miễn là không có người viết. Khóa ghi là độc quyền.

Bạn sẽ sử dụng tùy chọn này thay vì synchronized. Getters của bạn sẽ có được khóa đọc, sau đó phát hành khi họ quay trở lại, ví dụ:

public String getX() { 
    Lock readLock = readWriteLock.readLock(); 
    readLock.lock(); 
    try { 
     return value; 
    } finally { 
     readLock.unlock(); 
    } 
} 

Tương tự như phương pháp định vị, nhưng sử dụng readWriteLock.writeLock() thay thế.

Lớp học sẽ có một đối tượng ReentrantReadWriteLock duy nhất, được chia sẻ bởi tất cả các getters và setters trên mỗi đối tượng (hoặc, nếu bạn muốn, một cho mỗi cặp getter/setter).

Nó khá cồng kềnh, nhưng nên cho đồng thời tốt. Vì những lý do đó, bạn chỉ nên thực hiện điều này nếu bạn thực sự cần nó, và điều đó có nghĩa là đo lường sự đồng thời đã bị suy giảm mà bạn nhận được nếu bạn chỉ sử dụng đồng bộ hóa vanilla.

+0

Phương pháp tuyệt vời, Cảm ơn –

6

Trình thiết lập của bạn có thể lấy bản sao dữ liệu trên mỗi bản cập nhật và getters có thể sử dụng bản sao. Điều này có thể rất tốn kém cho setter, nhưng tác động tối thiểu cho getters.

Tuy nhiên, khóa được đồng bộ hóa có thể có thứ tự từ 25 đến 100 ns. Ngay cả khi bạn gọi một phương pháp đồng bộ một triệu lần mỗi phút, synchronized có thể không thêm đủ thời gian chờ để lo lắng. Tại một triệu mỗi giây, nó chắc chắn sẽ.

+0

ok sau đó nếu sự chậm trễ là theo thứ tự của ns tôi wouldnt tâm chỉ đồng bộ hóa tất cả các phương pháp. Cảm ơn vì thông tin. –

+0

Đoạn thứ hai của bạn dường như không liên quan. OP dường như không lo lắng về chi phí của chính 'đồng bộ'; thay vào đó, anh ta chỉ không muốn các cuộc gọi đến getter phải được tuần tự. (Tôi nghĩ anh đúng là anh ta không nên lo lắng, nhưng lý do không phải lo lắng là người khởi xướng phải rất nhanh chóng và rẻ tiền, không phải vì 'đồng bộ' là.) – ruakh

+0

Chi phí của 'đồng bộ hóa 'thường cao hơn nhiều so với phương thức gọi hàm getter. Nếu bạn getter là đắt hơn nhiều điều này, nó không phải là một getter thường xuyên. –

3

Trước tiên tôi sẽ đồng bộ hóa tất cả các truy cập và chỉ tối ưu hóa nếu điều đó chứng tỏ là vấn đề về hiệu suất.

Để tối ưu hóa, bạn có thể sử dụng một CopyOnWriteArrayList hoặc ReadWriteLock. Thật khó để đưa ra một giải pháp dứt khoát mà không biết bối cảnh chính xác hơn.

1

Đây là trường hợp nguyên mẫu để sử dụng một CopyOnWriteArrayList.

"Điều này thông thường quá tốn kém, nhưng có hiệu quả hơn các lựa chọn thay thế khi hoạt động truyền tải lớn hơn nhiều đột biến và hữu ích khi bạn không thể hoặc không muốn đồng bộ hóa các traversals, nhưng cần loại bỏ nhiễu giữa các chủ đề đồng thời."

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