2012-11-15 16 views
9

Vì vậy, tôi có mã tương tự như sauLàm thế nào để có được nhiều khóa mà không đặt hàng các ràng buộc trong Java?

synchronized(objectOne){ do stuff } 
synchronized(objectTwo){ do stuff } 

Vấn đề ở đây là chương trình sẽ chờ cho khóa trên , ngay cả khi khóa cho objectTwo có sẵn. Những gì tôi đang cố gắng làm là nói: cố gắng khóa cả hai và objectTwo và bất cứ lần nào bạn khóa trước tiên đều làm công cụ cho khóa đó. Tôi đã đưa ra một giải pháp nhưng tôi nghĩ rằng nó khá hacky và tôi tự hỏi nếu có ai có bất kỳ ý tưởng tốt hơn.

Đây là ý tưởng của tôi: Bắt đầu 2 chủ đề, mỗi chủ đề chờ một khóa và sau đó chuỗi chính sẽ đợi trên CountDownLatch. Vì vậy, bạn kết thúc với một cái gì đó như thế này:

CountDownLatch latch = new CountDownLatch(2); 

new Thread(new Runnable(){ 
public void run(){ 
    synchronized(objectOne) { do stuff } 
    latch.countDown(); 
}).start(); 

new Thread(new Runnable(){ 
public void run(){ 
    synchronized(objectTwo) { do stuff } 
    latch.countDown(); 
}).start(); 

latch.await(); 
+1

Điều đó nghe giống như cách tiếp cận hợp lý với tôi. – ArtB

+0

Tôi không thể nói bằng mã được đăng, nhưng theo kinh nghiệm của tôi, một lớp khóa trên hai đối tượng khác nhau hầu như luôn luôn được chia thành hai lớp, với khóa được đóng gói ** bên trong ** hai lớp, không phải bởi lớp tổng hợp chúng – Nate

+0

bạn đang sử dụng hai khóa khác nhau sao cho luồng B có thể không thấy sự thay đổi bộ nhớ của luồng A, tôi nghi ngờ sẽ không xảy ra - trước đây. –

Trả lời

5

Tôi nghĩ bạn nên sử dụng Lock cung cấp cho bạn phương pháp boolean tryLock().

Returns: true nếu khóa được mua và sai khác

Tiến hành làm công cụ khi bạn có ít nhất một trong những ổ khóa.

+0

Vì vậy, bạn có gợi ý một cái gì đó như liên tục cố gắng cả hai khóa cho đến khi bạn nhận được một trong hai, đóng gói bởi một số vòng lặp chờ đợi bận rộn? – user1825426

2

Bạn có thể muốn có 2 hàng đợi công việc, 2 luồng mỗi lần bỏ phiếu một hàng đợi và thực hiện công việc.

Đối với công việc liên quan đến objectOne, bạn đặt nó vào hàng đợi # 1; các công việc liên quan đến objectTwo trong hàng đợi # 2.

worker1.queue.put(new Runnable(){ public void run() { do stuff } }); 
worker2.queue.put(new Runnable(){ public void run() { do stuff } }); 

---- 

class Worker extends Thread 

    BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(); 

    public void run() 
     while(true) 
      queue.take().run(); 
0

Tùy thuộc vào số lượng stuff có thể tốn nhiều tiền hơn để tắt nhiều chuỗi để thực hiện. Nó chỉ có thể là tốt nhất để làm công cụ trong một chủ đề duy nhất nếu stuff là một hoạt động đủ nhanh. Bạn sẽ phải có thời gian để biết.

0

Tôi giống như hack của bạn, ít nhất là nếu đó là tình huống một lần. Điều đó nói rằng ...

Nếu bạn đang làm điều này rất nhiều và muốn một cái gì đó "ít hacky", tôi đề nghị ExecutorService#invokeAll(). Điều này có một danh sách các cuộc gọi, thực hiện chúng trên một hồ bơi thread và khối cho đến khi tất cả chúng được thực hiện.

Phác thảo:

ExecutorService es = Executors.newCachedThreadPool(); // for example... 
List<Future<Void>> results = es.invokeAll(new ArrayList {{ 
     add(new Callable<Void> { 
      public Void call() { synchronized(objectOne) { do stuff } } 
     }); 
     add(new Callable<Void> { 
      public Void call() { synchronized(objectTwo) { do stuff } } 
     }); 
    }}); 
// both Callables are done when you get here 

Điều này rõ ràng giả định rằng đó là ok để gọi những phương pháp từ chủ đề khác nhau vào thời điểm này trong ứng dụng của bạn. Nếu vì lý do nào đó bạn cần phải gọi cả hai từ cùng một chủ đề, tôi nghĩ rằng bạn đang cam chịu sử dụng tryLock và bận-chờ đợi như được thảo luận trong câu trả lời của Bhesh Gurung.

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