是否有可能在一种方法中获得锁并从另一种方法中释放它?

问题描述:

我基本上使用了一个框架工作,它调用了来自两个不同线程的一堆函数。我希望在下一个线程允许继续之前完成一个完整的线程。但是,我无法改变代码。是否有可能在一种方法中获得锁并从另一种方法中释放它?

例如假设有两个线程,线程1和线程2.每个线程调用方法一到三。

所以,你得到一个调用顺序是这样的:

 
T1-M1 
T1-M2 
T2-M1 
T1-M3 
T2-M2 
T2-M3 

不过,我想有发生的情况是T1-M1一个什么套某种锁会阻塞T2的,所以订货会作为如下。

 
T1-M1 - get lock 
     T2-M1 - blocked 
T1-M2 
T1-M3 - release lock 

T2-M1 - no longer blocked - gets lock 
T2-M2 
T2-M3 

是否有可能在没有从框架编辑调用方法的情况下在Java中执行此操作?

+0

你的代码/问题对我毫无意义。如果您有两个线程,并且线程1必须在线程2可以运行之前完成,则不需要两个线程。 Thread1可以做它的第一部分,然后它是第二部分(在等待thread1完成之后,部分thread2会做)。 – 2011-05-05 15:57:07

+0

@Ken:据我所知,他是“M1”,“M2”和“M3”的作者,这些方法由其他一些在“T1”和“T2”中运行的外部代码调用。 – 2011-05-05 15:57:58

+0

@Joachim Sauer是的,这是正确的。 – 2011-05-05 17:48:35

您不能用​​关键字提供的简单功能来做到这一点:它的锁必须被释放在它所获取的相同方法(偶数块)。

但是,您可以使用java.util.concurrent.locks中的工具。

这是ReentrantLock这个类几乎是​​机制的reification

但请记住,这种方法是危险的。如果一个线程调用M1M2,但从未调用M3?例如,在M2M3之间的某些代码中可能会出现异常。

+0

[CountDownLatch](http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html)如何? – 2011-05-05 15:54:30

+0

我认为这里的目标是相互排斥。换句话说,如果第三个线程'T3'想运行'M1',而'T2'运行'M2',那么它也应该阻塞。这不能真正用'CountDownLatch'来实现,但是对于'ReentrantLock'来说是微不足道的。 – 2011-05-05 15:56:46

您不能从另一个方法释放内部锁,但可以从另一个方法释放j.u.c.Lock。例如:(基于彼得Lawrey的响应编辑,感谢)

public boolean tryAcquireTimedLock(){ 
    return lock.tryLock(30, TimeUnit.SECONDS); 
} 

public void releaseLock(){ 
    lock.unlock(); 
} 

这里提供了一个方便的方法与超时interruptbly获取锁。

现在让我们找到陷阱。如果您使用不同的方法锁定和解锁,则必须小心在此过程中可能发生的任何异常。未能解释这可能会导致死锁问题。

public void doSomeWork(){ 
    if(tryAcquireTimedLock()){ 

     otherMethodWork(); 

     finalMethodWork(); 
    } 
} 


public void otherMethodWork(){ 
    //do something that may cause an Exception 
} 

public void finalMethodWork(){ 
    //finish work now release lock 
    releaseLock(); 
} 

现在,如果otherMethodWork()抛出一个RuntimeException?您的代码现在将永远无法调用releaseLock(),并且无法取得更多进展。

这就是为什么它被指示使用的样式

lock.lock(); 
try{ 
    //work 
}finally{ 
    lock.unlock(); 
} 

如果任何错误发生在工作//你仍然可以解锁并取得进展。

+0

+1:如果tryLock失败,解锁将抛出异常。您可能想要返回说明它是否被锁定的布尔值。 – 2011-05-05 16:49:33

+0

@Peter Lawrey:好点,编辑来反映这个想法。 – 2011-05-05 17:28:03

+0

@JOhn V.你还推荐ReentrantLock? – 2011-05-05 17:55:37

如果你不想控制来自框架层的调用,你可以通过将这个逻辑设置到每个你可以访问每个单一方法的线程中来进行验证,你可以使用会话变量作为标志,例如控制何时该方法可用于任何其他方法,以便您可以调用线程并且他们将具有访问方法的验证。 -

只是其他帖子的补充,所有3个方法必须共享相同的锁,这里的共享资源是3个方法的捆绑,您不希望T1在T2和T2上锁定M1和M2已经锁定了M3。

+0

谢谢。这就说得通了。 – 2011-05-08 20:32:50