2012-02-15 37 views
11

Tôi muốn có thể khóa dựa trên hệ thống phân cấp hệ thống tệp. Ví dụ:Khóa mutex phân cấp trong Java

Chủ đề 1:

lock("/"); 
doStuff(); 
unlock(); 

Chủ đề 2:

lock("/sub/foo"); 
doStuff(); 
unlock(); 

Chủ đề 3:

lock("/sub/bar"); 
doStuff(); 
unlock(); 

Nếu Chủ đề 1 mua lại khóa đầu tiên sau đó đề 2 và 3 sẽ bị chặn cho đến khi Thread 1 mở khóa. Tuy nhiên, nếu Thread 2 mua lại khóa đầu tiên, thì Thread 3 sẽ có thể thực hiện cùng lúc với Thread 2. Quy tắc chung là nếu có khóa trên thư mục cha, thì thread phải chặn.

Java có tích hợp bất cứ thứ gì có thể giúp giải quyết vấn đề này không? Tôi muốn tránh lưu trữ một khóa cho mỗi thư mục vì sẽ có hàng trăm ngàn thư mục.

+0

+1 cho một câu hỏi thú vị nghiêm túc. Cấu trúc thư mục được chỉ định trước hay có thể tạo các tệp "ad-hoc" không? Ngoài ra, hệ thống ưu tiên là gì nếu một luồng muốn lấy thư mục gốc trong khi nhiều chủ đề khác cố gắng lấy các tệp riêng lẻ?Liệu sợi chỉ muốn gốc chỉ chết đói, hay có một số loại bảo đảm bạn có trong tâm trí? – templatetypedef

+0

Tôi giả sử rằng nếu Thread 2 mua lại khóa, Thread 1 sẽ chặn, phải không? – Irfy

+0

Một phần của động lực đằng sau việc này là sửa đổi hệ thống tệp, vì vậy các đường dẫn sẽ liên tục thay đổi. Tôi không chắc chắn làm thế nào để xử lý đói đói ... đó là một cái gì đó tôi đã không thực sự xem xét. Tôi cho rằng cơ chế khóa đọc/ghi có thể tiến gần đến việc giải quyết vấn đề này và có thể xử lý các luồng không bị đói. –

Trả lời

7

tôi muốn lưu trữ các đường dẫn thư mục trong một cây như thế này:

-/
- sub 
    - foo 
    - bar 

Bất cứ khi nào bạn cần để khóa bất cứ điều gì trong cây mà bạn đi xuống từ gốc và có được một đọc khóa trên tất cả mọi thứ ngoại trừ các mục tiêu nút chính nó. Nút đích nhận khóa ghi.

Đề án này đảm bảo cho bạn sự tự do bế tắc và sự ổn định của các phần liên quan của cây.

Tôi không thấy sự cố cụ thể lưu trữ hàng trăm nghìn khóa. Điều này có lẽ sẽ lãng phí 100 byte RAM mỗi khóa. Nhưng nó đơn giản hóa kiến ​​trúc. Bạn có đo lường nếu nó thực sự là một vấn đề?

Thay vào đó, bạn có thể có bản đồ từ đường dẫn đến khóa. Tất cả các thao tác trên từ điển đó phải được đồng bộ hóa bởi người gọi. Điều này cho phép bạn lười biếng khởi tạo khóa. Bạn cũng có thể định kỳ thu thập rác không sử dụng các khóa bằng cách đầu tiên ghi một khóa trên thư mục gốc mà không cho phép tất cả các hoạt động. Khi mọi thứ đều im lặng, bạn loại bỏ tất cả các khóa không phải root.

+1

Cách tiếp cận thú vị. Tôi nghĩ rằng có thể làm việc. Nếu tôi phải lưu trữ một khóa cho mỗi thư mục, thì cũng vậy. Tôi chỉ cố tránh nó nếu có thể. –

+0

Đây là cách cơ sở dữ liệu thực hiện khóa của chúng. Chúng khóa con đường B-tree từ gốc xuống các trang lá. – usr

+0

Điều này có vẻ tốt. Tôi sẽ đi với một 'java.util.ConcurrentHashMap' cho hiệu năng tốt nhất và tôi sẽ ánh xạ nó thành' '. Tôi cũng sẽ sử dụng 'File file = new File (stringPath) .getCanonicalFile()' để đảm bảo tính duy nhất. Logic sau đó nên được khá rõ ràng cho tạo khóa lười biếng và khóa riêng biệt để đọc và viết. – Irfy

0

Có thể có giải pháp hiệu quả hơn, nhưng dưới đây là cách tôi sẽ bắt đầu.

Tôi sẽ tạo đối tượng TreeAccess được chia sẻ, với lock(path) và phương thức unlock(path). Phương pháp này sẽ phải nhập một khối đồng bộ sẽ lặp lại cho đến khi đường dẫn có sẵn. Tại mỗi lần lặp lại, nếu không có sẵn, nó sẽ kiểm tra xem đường dẫn có sẵn không và nếu không, wait() cho đến khi một số luồng khác gọi notifyAll(). Nếu đường dẫn có sẵn, sau đó nó sẽ tiến hành, và khi thực hiện xong, hãy gọi phương thức unlock() sẽ là notifyAll().

Trước khi tiếp tục, bạn phải lưu trữ đường dẫn bị khóa vào một số cấu trúc dữ liệu. Và trước khi thông báo, bạn phải xóa đường dẫn đã mở khỏi cấu trúc dữ liệu này. Để kiểm tra xem đường dẫn có khả dụng không, bạn cần phải tìm xem có tồn tại một số đường dẫn trong cấu trúc dữ liệu này bằng hoặc là tổ tiên của đường dẫn bạn muốn khóa.

public void lock(String path) { 
    synchronized (lock) { 
     while (!available(path)) { 
      lock.wait(); 
     } 
     lockedPaths.add(path); 
    } 
} 

public void unlock(String path) { 
    synchronized (lock) { 
     lockedPaths.remove(path); 
     lock.notifAll(); 
    } 
} 

private boolean available(String path) { 
    for (String lockedPath : lockedPaths) { 
     if (isParentOrEqual(lockedPath, path) { // this method is left as an exercise 
      return false; 
     } 
    } 
    return true; 
} 
Các vấn đề liên quan