java 死锁和同步方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6260038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Deadlocks and Synchronized methods
提问by Carven
I've found one of the code on Stack Overflow and I thought it is pretty similar to what I am facing but I still don't understand why this would enter a deadlock. The example was taken from Deadlock detection in Java:
我在 Stack Overflow 上找到了其中一个代码,我认为它与我面临的非常相似,但我仍然不明白为什么这会进入僵局。该示例取自Java 中的死锁检测:
Class A
{
synchronized void methodA(B b)
{
b.last();
}
synchronized void last()
{
System.out.println(“ Inside A.last()”);
}
}
Class B
{
synchronized void methodB(A a)
{
a.last();
}
synchronized void last()
{
System.out.println(“ Inside B.last()”);
}
}
Class Deadlock implements Runnable
{
A a = new A();
B b = new B();
// Constructor
Deadlock()
{
Thread t = new Thread(this);
t.start();
a.methodA(b);
}
public void run()
{
b.methodB(a);
}
public static void main(String args[] )
{
new Deadlock();
}
}
In this case, when the Deadlock() constructor is called, it starts itself as a thread. When it does this, the run() method is invoked. It will call b.methodB(a), which then calls a.last() to just print out a statement. At the same time, a.methodA(b) would call b.last(). There is no cross dependencies on any object and they are not executing a method at a same time too. Even if they are, the synchronized keyword would queue them, wouldn't it? But how come this would occasionally enter a deadlock too? It is not all the time but it would sometimes enter a deadlock, which is quite unpredictable. What is it that causes this to go into a deadlock and workarounds?
在这种情况下,当调用 Deadlock() 构造函数时,它作为一个线程启动自己。执行此操作时,将调用 run() 方法。它将调用 b.methodB(a),然后调用 a.last() 来打印一条语句。同时,a.methodA(b) 会调用 b.last()。对任何对象都没有交叉依赖,它们也不会同时执行一个方法。即使它们是,synchronized 关键字也会将它们排入队列,不是吗?但这怎么偶尔也会陷入僵局呢?并非总是如此,但有时会进入僵局,这是非常不可预测的。是什么导致这种情况陷入僵局和解决方法?
回答by matt b
It is possible that the execution of these two statements is interweaved:
有可能这两条语句的执行是交织在一起的:
Thread 1: a.methodA(b); //inside the constructor
Thread 2: b.methodB(a); //inside run()
to execute a.methodA()
, Thread 1 will need to obtain the lock on the A
object.
要执行a.methodA()
,线程 1 将需要获取A
对象上的锁。
to execute b.methodB()
, Thread 2 will need to obtain the lock on the B
object.
要执行b.methodB()
,线程 2 需要获取B
对象上的锁。
For Thread 1's methodA()
to then be able to call the sychronized method on the b
instance, it will need to obtain the lock on b
being held by Thread 2, which will cause Thread 1 to wait until that lock is freed.
为了让线程 1methodA()
能够调用b
实例上的同步方法,它需要获取b
线程 2 持有的锁,这将导致线程 1 等待该锁被释放。
For Thread2's methodB()
to be able to call the synchronized method on the a
instance, it will need to obtain the lock being held on a
by Thread 1 - which will cause Thread 2 to wait as well.
为了让线程 2methodB()
能够调用a
实例上的同步方法,它需要获得a
线程 1持有的锁——这将导致线程 2 也等待。
Since each thread is holding a lock that the other thread wants, a deadlock will occur where neither thread is able to obtain the lock it wants, and neither thread will release the locks that it doeshold.
因为每个线程持有另一个线程需要的锁,就会发生死锁,其中两个线程能够获得它想要的锁,两个线程将释放锁,它确实持有。
It's important to understand that this code will not produce a deadlock 100% of the time you run it - only when the four crucial steps (Thread1 holds A's lock and tries to obtain B, which Thread 2 holds B's lock and tries to obtain A's) are executed in a certain order. Run this code enough times and that order is bound to happen though.
重要的是要理解,此代码不会在您运行时 100% 产生死锁 - 只有在四个关键步骤(线程 1 持有 A 的锁并尝试获取 B,线程 2 持有 B 的锁并尝试获取 A 的锁)时才会产生死锁是按照一定的顺序执行的。运行这段代码足够多的次数,但这个顺序肯定会发生。
回答by sarnold
synchronized
places a lock on the objectthat must be acquired before the methods or codeblocks can execute. Because it locks entire objects, it is an inelegant tool that sometimes looks pretty easy to use, but gives deadlocks like this, where no actual contested data is being read or written.
synchronized
在方法或代码块可以执行之前必须获取的对象上放置一个锁。因为它锁定了整个对象,所以它是一个不优雅的工具,有时看起来很容易使用,但会产生像这样的死锁,没有实际的有争议的数据正在被读取或写入。
a.method(b)
locks the a
object. b.method(a)
locks the b
object. And neither thread of execution can continue on to calling b.last()
or a.last()
, because they are both waiting for the other object to release its lock.
a.method(b)
锁定a
对象。b.method(a)
锁定b
对象。并且两个执行线程都不能继续调用b.last()
或a.last()
,因为它们都在等待另一个对象释放其锁。
回答by david van brink
Calling methodA does (effectively) lock(a), lock(b). If the task switches then and tries methodB, it hits lock(b) right then.
调用 methodA 确实(有效地)lock(a)、lock(b)。如果任务切换然后尝试methodB,它就会立即命中lock(b)。