Tôi muốn đồng bộ hóa các cuộc gọi phương thức trên cơ sở một số id giống như một Trang trí đồng thời của một cá thể đối tượng nhất định.
Ví dụ:
Tất cả các chuỗi gọi phương thức có tham số "id1", nên thực thi serially với nhau.
Tất cả các phần còn lại, gọi phương thức với đối số khác nhau, nói "id2", nên thực hiện song song với các chuỗi gọi phương thức có tham số "id1", nhưng lại liên tục với nhau.Đồng bộ hóa/khóa các cuộc gọi phương thức hạt mịn dựa trên các tham số phương pháp
Vì vậy, trong tâm trí của tôi điều này có thể được thực hiện bằng cách có một khóa (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantLock.html) trường hợp cho mỗi tham số phương pháp như vậy. Mỗi lần phương thức được gọi với thông số, trường hợp khóa tương ứng với giá trị param cụ thể (ví dụ: "id1") sẽ được tìm kiếm và chuỗi hiện tại sẽ cố gắng lấy khóa.
Phát biểu trong mã:
public class ConcurrentPolicyWrapperImpl implements Foo {
private Foo delegate;
/**
* Holds the monitor objects used for synchronization.
*/
private Map<String, Lock> concurrentPolicyMap = Collections.synchronizedMap(new HashMap<String, Lock>());
/**
* Here we decorate the call to the wrapped instance with a synchronization policy.
*/
@Override
public Object callFooDelegateMethod (String id) {
Lock lock = getLock(id);
lock.lock();
try {
return delegate.delegateMethod(id);
} finally {
lock.unlock();
}
}
protected Lock getLock(String id) {
Lock lock = concurrentPolicyMap.get(id);
if (lock == null) {
lock = createLock();
concurrentPolicyMap.put(id, lock);
}
return lock;
}
}
protected Lock createLock() {
return new ReentrantLock();
}
Dường như việc này - Tôi đã làm một số thử nghiệm hiệu suất với jmeter và vân vân. Tuy nhiên, như chúng ta đều biết rằng sự tương tranh trong Java là một điều phức tạp, tôi quyết định hỏi ý kiến của bạn ở đây.
Tôi không thể ngừng nghĩ rằng có thể có cách tốt hơn để thực hiện việc này. Ví dụ bằng cách sử dụng một trong các triển khai BlockingQueue. Bạn nghĩ sao?
Tôi cũng không thể thực sự quyết định xem có vấn đề đồng bộ hóa tiềm năng nào với việc khóa hay không, tức là phương pháp protected Lock getLock(String id)
. Tôi đang sử dụng một bộ sưu tập đồng bộ, nhưng là đủ? I E. không phải là nội dung như sau thay vì nội dung tôi hiện có:
protected Lock getLock(String id) {
synchronized(concurrentPolicyMap) {
Lock lock = concurrentPolicyMap.get(id);
if (lock == null) {
lock = createLock();
concurrentPolicyMap.put(id, lock);
}
return lock;
}
}
Vậy các bạn nghĩ sao?
Bạn đang nói "Khóa vấn đề sáng tạo sang một bên" ... Bạn có phát hiện ra bất kỳ hoặc ý của bạn là bạn không bình luận về nó? – Svilen
Nhìn vào vấn đề đó chặt chẽ hơn bây giờ-- vâng, bạn sẽ definitley cần khối đồng bộ trong phương thức getLock() của bạn. Như bạn có trong ví dụ thứ hai. Nếu không, hình ảnh (a) 5 chủ đề gọi getLock() cùng một lúc, cho cùng một ID; (b) tất cả đều tìm thấy khóa null; (c) tất cả chúng tạo ra và trả về một thể hiện khóa mới. Thất bại. Khối đồng bộ hóa trong mã bit thứ hai của bạn tránh được điều đó. – Keith
Cảm ơn, Keith. Btw, bạn có lẽ có bất kỳ ý tưởng làm thế nào để làm điều tương tự nhưng với các nhà điều hành/nhiệm vụ. I E. có một ThreadPoolExecutor duy nhất nhưng thực hiện nhiệm vụ phân vùng bằng một khóa. Ví dụ các nhiệm vụ cho khóa "id1" sẽ chạy theo kiểu nối tiếp với nhau, đồng thời song song với tất cả các nhiệm vụ khác cho các khóa "id2", "id3", vv ... – Svilen