2012-06-20 30 views
14

Cách tốt nhất để ngăn cập nhật đồng thời một bản ghi trong bộ khóa-giá trị mà không khóa toàn bộ tập hợp là gì? Ngữ nghĩa, tôi đang tìm một số loại khóa bằng chìa khóa (lý tưởng, thực hiện Java, nhưng không nhất thiết):Cách lấy khóa bằng

interface LockByKey { 
    void lock(String key); // acquire an exclusive lock for a key 
    void unlock(String key); // release lock for a key 
} 

khóa này được thiết kế để đồng bộ hóa quyền truy cập vào một cửa hàng từ xa, vì vậy một số bộ sưu tập Java đồng bộ không phải là một sự lựa chọn.

+1

Điều này có liên quan đến cách bạn đồng bộ hóa quyền truy cập vào cửa hàng từ xa của mình. Không chắc chắn nếu câu hỏi này có thể được trả lời mà không biết thêm về cách bạn quản lý đồng thời từ xa. –

+0

Hãy xem http://stackoverflow.com/a/28347825/704335. – Timmos

+0

Bạn có thể sử dụng: http://stackoverflow.com/a/28723518/1183010 –

Trả lời

25

Ổi có thứ gì đó như thế này đang được phát hành ở 13.0; bạn có thể lấy nó ra khỏi HEAD nếu bạn muốn.

Striped<Lock> nhiều hoặc ít phân bổ số lượng khóa cụ thể và sau đó gán chuỗi cho khóa dựa trên mã băm của chúng. API trông nhiều hơn hoặc ít hơn như

Striped<Lock> locks = Striped.lock(stripes); 
Lock l = locks.get(string); 
l.lock(); 
try { 
    // do stuff 
} finally { 
    l.unlock(); 
} 

Nhiều hơn hoặc ít hơn, số lượng kiểm soát của sọc cho phép bạn giao dịch đồng thời chống lại việc sử dụng bộ nhớ, bởi vì phân bổ một khóa đầy đủ cho mỗi phím chuỗi có thể tốn kém; về cơ bản, bạn chỉ nhận được tranh chấp khóa khi bạn nhận được va chạm băm, đó là (dự đoán) hiếm.

(Tiết lộ: Tôi đóng góp cho ổi.)

+0

bộ nhớ kết hợp với ổ khóa cũ có được làm sạch không? giống như họ sẽ được lưu giữ trong WeakHashMap. –

+2

Nó sẽ xảy ra nếu bạn sử dụng phương thức factory để tạo khóa yếu. –

+1

@ Jose Martinez: không, nó không làm sạch bất cứ điều gì, nó không phải, nó hoạt động trên một nguyên tắc khác nhau. Lấy ví dụ 'Striped.lock (1024)', tạo mảng Lock [1024] đơn giản, háo hức khởi tạo với 1024 đối tượng Lock được tạo trước; xem 'Striped.CompactStriped'. Bạn có thể có ứng dụng với hàng tỷ ID duy nhất nhưng hồ bơi khóa của bạn luôn ở mức 1024 luôn có cùng Khóa. 'Sọc' hoạt động trên xác suất VERY thấp có ý nghĩa thống kê 2 hoặc nhiều hơn, các ID tạo ra cùng một giá trị băm cố gắng truy cập vào mutex cùng một lúc. – Espinosa

0

Giữ một mutex/khóa trên mỗi nhóm. Điều này sẽ đảm bảo rằng chỉ có va chạm chờ đợi trên mutex đó.

0

Nếu "bản ghi" bạn đề cập là đối tượng có thể thay đổi và "cập nhật" có nghĩa là trạng thái bên trong của đối tượng được sửa đổi mà không làm xáo trộn cấu trúc của vùng chứa, bạn có thể thực hiện những gì mình muốn bằng cách khóa đối tượng bản ghi.

Nếu tuy nhiên "cập nhật" có nghĩa là xóa đối tượng bản ghi khỏi vùng chứa và thay thế nó, thì bạn phải khóa toàn bộ vùng chứa để ngăn các chủ đề khác nhìn thấy nó trong trạng thái không nhất quán.

Trong cả hai trường hợp, bạn nên xem các lớp học trong gói java.util.concurrent.

1

Đây là cách thực hiện; Tôi đã làm nó. Và có, tôi đồng ý nếu hai chuỗi khác nhau chia sẻ cùng một hashcode sẽ kết thúc bằng việc mua cùng một khóa.

class LockByKey { 
    ObjectForString objHolder = new ObjectForString(100); 
    public void lockThenWorkForKey (String key) { 
     synchronized(objHolder.valueOf(key)){ 
      //DoSomeWork 
     } 
    } 
} 

public final class ObjectForString { 

    private final Object[] cache; 
    private final int cacheSize; 
    final int mask; 

    public ObjectForString(int size) { 
     // Find power-of-two sizes best matching arguments 
     int ssize = 1; 
     while (ssize < size) { 
      ssize <<= 1; 
     } 

     mask = ssize - 1; 
     cache = new Object[ssize]; 
     cacheSize = ssize; 
     //build the Cache 
     for (int i = 0; i < cacheSize; i++) { 
      this.cache[i] = new Object(); 
     } 
    } 

    public Object valueOf(String key) { 
     int index = key.hashCode(); 
     return cache[index & mask]; 
    } 
} 
Các vấn đề liên quan