如何在Java中没有排序约束的情况下获取多个锁?

时间:2012-11-15 01:49:46

标签: java concurrency locking

所以我的代码与此类似

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

问题是,即使objectOne的锁定可用,程序也会等待objectTwo上的锁定。我要做的就是说:尝试同时锁定objectOneobjectTwo,无论你先获得哪个锁都可以锁定该锁。我想出了一个解决方案,但我觉得它很苛刻,我想知道是否有人有更好的想法。

这是我的想法:启动2个线程,每个线程等待锁定,然后主线程将等待CountDownLatch。所以你最终得到这样的东西:

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();

4 个答案:

答案 0 :(得分:5)

我认为你应该使用Lock为你提供方法boolean tryLock()

  

返回:           如果获得了锁定,则为true,否则为

当你至少有一把锁时,继续做一些事情。

答案 1 :(得分:2)

您可能希望拥有2个作业队列,每个队列轮询2个线程并执行作业。

对于与objectOne相关的作业,将其放入队列#1;队列#2中与objectTwo相关的作业。

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();

答案 2 :(得分:0)

根据stuff的数量,分离多个线程来执行操作可能会带来更多开销。如果stuff是足够快的操作,那么在单个线程中执行操作可能是最好的。你必须知道它的时间。

答案 3 :(得分:0)

我有点像你的黑客,至少如果它是一次性的情况。那说......

如果你经常做这类事情并想要一些事情,那就不那么苛刻了,我建议ExecutorService#invokeAll()。这将获取一个Callables列表,在线程池中执行它们并阻塞,直到它们全部完成。

草图:

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

这显然假设您可以在应用中的此时从不同的线程调用这些方法。如果由于某种原因你需要从同一个帖子中调用两者,我认为你注定要使用tryLock并忙于等待Bhesh Gurung的回答中所讨论的。