以下是我发现的关于死锁的一个例子,它有效。我的问题是currentThread()
如何运作?并且A和B也不是专门创建的线程,即:
Deadlock d=new Deadlock();
Thread A=new Thread(d)
代码如何运作?
class A {
synchronized void foo(B b) {
String name = Thread.currentThread().getName();
System.out.println(name + " entered A.foo");
try {
Thread.sleep(1000);
} catch (Exception e) {System.out.println("A Interrupted");
}
System.out.println(name + " trying to call B.last()");
b.last();
}
synchronized void last() {
System.out.println("Inside A.last");
}
}
class B {
synchronized void bar(A a) {
String name = Thread.currentThread().getName();
System.out.println(name + " entered B.bar");
try {
Thread.sleep(1000);
} catch (Exception e) {System.out.println("B Interrupted");
}
System.out.println(name + " trying to call A.last()");
a.last();
}
synchronized void last() {
System.out.println("Inside A.last");
}
}
public class Deadlock implements Runnable {
A a = new A();
B b = new B();
Deadlock() {
Thread.currentThread().setName("MainThread");
Thread t = new Thread(this, "RacingThread");
t.start();
a.foo(b); // get lock on a in this thread.
System.out.println("Back in main thread");
}
public void run() {
b.bar(a); // get lock on b in other thread.
System.out.println("Back in other thread");
}
public static void main(String args[]) {
new Deadlock();
}
}
答案 0 :(得分:2)
我认为这是一个相当混乱的死锁示例 - 它会给问题增加其他噪音。
使用Lock
这样的对象可以实现一个非常简单的例子:
public class App {
private static final Lock LOCKA = new ReentrantLock();
private static final Lock LOCKB = new ReentrantLock();
private static final class Locker1 implements Runnable {
@Override
public void run() {
while (true) {
try {
LOCKA.lockInterruptibly();
Thread.sleep(100);
LOCKB.lockInterruptibly();
System.out.println("Locker 1 Got locks");
} catch (InterruptedException ex) {
return;
}
LOCKB.unlock();
LOCKA.unlock();
}
}
}
private static final class Locker2 implements Runnable {
@Override
public void run() {
while (true) {
try {
LOCKB.lockInterruptibly();
Thread.sleep(100);
LOCKA.lockInterruptibly();
System.out.println("Locker 2 Got locks");
} catch (InterruptedException ex) {
return;
} finally {
LOCKA.unlock();
LOCKB.unlock();
}
}
}
}
public static void main(String[] args) throws IOException {
final ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new Locker1());
executorService.submit(new Locker2());
}
}
应用程序在执行程序中启动两个线程,然后我们让这些线程调用两个runnables。
这些runnables尝试以相反的顺序获取两个Lock
对象的锁。
所以Locker1
锁定LOCKA
然后等待几毫秒。 Locker2
锁定LOCKB
并等待几毫秒,他们尝试获取另一个锁。
情况是Locker1
等待LOCKB
和Locker2
等待LOCKA
,因为另一个线程永远不会释放它。
您可以在这些线程的线程转储中相当清楚地看到这一点:
"pool-1-thread-1" - Thread t@8
java.lang.Thread.State: WAITING
at sun.misc.Unsafe.park(Native Method)
- waiting to lock <7725204d> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) owned by "pool-1-thread-2" t@9
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:894)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
at com.boris.testbench.App$Locker1.run(App.java:32)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
Locked ownable synchronizers:
- locked <7567e1fa> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
- locked <5ad52411> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"pool-1-thread-2" - Thread t@9
java.lang.Thread.State: WAITING
at sun.misc.Unsafe.park(Native Method)
- waiting to lock <7567e1fa> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) owned by "pool-1-thread-1" t@8
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:894)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
at com.boris.testbench.App$Locker2.run(App.java:51)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
Locked ownable synchronizers:
- locked <7725204d> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
- locked <6856c528> (a java.util.concurrent.ThreadPoolExecutor$Worker)
我们可以看到pool-1-thread-1
希望锁定pool-1-thread-2
拥有的锁定,而pool-1-thread-2
希望锁定pool-1-thread-1
拥有的锁定。
这种情况将永远持续下去,因此陷入僵局。
您的代码实现了相同的结果,但不是使用手动生成的两个线程,而是使用应用程序主线程(由JVM生成)和一个手动生成的线程。
它还在两个synchronized
s而不是两个Object
对象中使用Lock
个方法。
答案 1 :(得分:2)
Thread#currentThread()
=当前正在运行的线程。一切都在线程中运行。当你启动一个java应用程序时,你只有一个我们可以调用主线程的线程。因此,调用main
方法只不过是正在运行的线程的开始。
我评论你可能有些疑惑。
// Deadlock is a Runnable. So, it can be wrapped inside a Thread Object to be started.
public class Deadlock implements Runnable {
A a = new A();
B b = new B();
Deadlock() {
// currentThread now is the one that instanciated this Deadlock object.
Thread.currentThread().setName("MainThread");
// here the Deadlock is wrapped inside a thread object. Notice the `this` qualifier.
Thread t = new Thread(this, "RacingThread");
// here the thread wrapping deadlock is started.
t.start();
a.foo(b); // get lock on a in this thread.
System.out.println("Back in main thread");
}
public void run() {
b.bar(a); // get lock on b in other thread.
System.out.println("Back in other thread");
}
// here is the start of the Main Thread! :D
public static void main(String args[]) {
// the program is started inside the Deadlock Class constructor.
new Deadlock();
}
}
你现在能更好地理解吗?
答案 2 :(得分:1)
这里有一些好的答案(+1给@Ralf和@ bmorris591),但我想我会更多地解释你的代码。
这里有2个主题。运行main(...)
和"RacingThread"
的“主”线程从Deadlock
构造函数中开始。顺便说一句,在对象构造函数中启动一个线程是非常糟糕的形式。做一些像这样的事情会更好:
Deadlock deadlock = new Deadlock();
new Thread(deadlock, "RacingThread").start();
此外,在Deadlock
构造函数中,它调用Thread.currentThread().setName("MainThread");
。这是尝试设置当前正在运行的线程的名称,因为它执行了new Deadlock()
,因此(令人困惑地)是“主”线程。不幸的是,如果线程已经在运行,那么setName(...)
调用是noop,因此它不会执行任何操作。
接下来,在Deadlock
构造函数中,"RacingThread"
由this
构建,Runnable
和start()
被调用,它会分叉线程并拥有它调用Deadlock.run()
方法。这需要一些时间,因此在调用a.foo(b);
方法之前,很可能会在之前到达run()
行。
您的a
和b
个对象不是线程已经指出了。它们只是用于演示锁定的对象。发生死锁是因为主线程正在调用a.foo(b);
,然后"RacingThread"
调用b.bar(a);
方法内的run();
。 a.foo(...)
上的synchronized
为a
,然后尝试在b.last()
上致电synchronized
b
。 b.bar(...)
上的synchronized
为b
,然后尝试在a.last()
上致电synchronized
a
。这是一个典型的僵局。
希望这有点帮助。
答案 3 :(得分:0)
我认为您假设synchronized关键字是全局锁定。它不是。它只是锁定(序列化)访问它所应用的方法。鉴于您的示例不会从2个单独的线程在同一个类上调用相同的方法,因此没有理由不起作用。
答案 4 :(得分:0)
当2个线程以不同的顺序获取两个资源时发生死锁:
这个程序:
public class DeadLock implements Runnable {
String name;
Object r1;
Object r2;
DeadLock( String name, Object r1, Object r2 ) {
this.name = name;
this.r1 = r1;
this.r2 = r2;
}
@Override public void run() {
if( name.equals( "T1" )) {
System.out.println( name + " try to take r1" );
synchronized( r1 ) {
System.out.println( name + " has taken r1" );
try{ Thread.sleep( 1000L ); }catch( InterruptedException x ){}
System.out.println( name + " try to take r2" );
synchronized( r2 ) {
System.out.println( name + " has taken r2" );
}
}
}
else {
System.out.println( name + " try to take r2" );
synchronized( r2 ) {
System.out.println( name + " has taken r2" );
try{ Thread.sleep( 1000L ); }catch( InterruptedException x ){}
System.out.println( name + " try to take r1" );
synchronized( r1 ) {
System.out.println( name + " has taken r1" );
}
}
}
}
public static void main( String[] args ) {
Object r1 = new Object();
Object r2 = new Object();
new Thread( new DeadLock( "T1", r1, r2 )).start();
new Thread( new DeadLock( "T2", r1, r2 )).start();
}
}
输出:
T1 try to take r1
T2 try to take r2
T1 has taken r1
T2 has taken r2
T2 try to take r1
T1 try to take r2