回顾一下对象锁
创建一个线程MyThread2并继承Thread类,重写run方法
class MyThread2 extends Thread{
private StringBuilder sb;
public MyThread2(StringBuilder sb){
this.sb = sb;
}
@Override
public void run() {
//run方法持有 sb 的锁
synchronized(sb){
sb.reverse();
}
System.out.println(sb.toString());
}
}
测试方法
public class TestObjectLock {
public static void main(String[] args) {
// 创建 sb 对象作为下面的的锁
StringBuilder sb = new StringBuilder("ABCDEFG");
MyThread2 mt2 = new MyThread2(sb);
mt2.start();
synchronized (sb) {
try {
// 线程 mt2 获得cpu执行权
mt2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("sb-->"+sb);
}
}
结果是没有任何输出,线程产生了死锁
分析
线程mt2创建的时候把sb对象传入到mt2对象内部,调用start方法调用run方法,synchronized(sb){…}中使用sb作为对象锁,锁定代码块。
回到主线程,当主线程synchronized(sb){…}中也使用sb作为对象锁,在同步代码块中mt2.join(),把cpu执行权让给mt2,主线程进入阻塞状态,但是并没有释放对象锁sb,等待mt2运行完毕。
但是由于main线程此时拥有对象锁sb,mt2无法拥有sb的锁,导致mt2等待主线程运行完之后才能运行,
此时就产生了这样的情况,主线程阻塞等替代mt2线程运行完才能运行,但是,mt2线程又因为要等待主线程运行完释放对象锁sb,而处在等待状态,所以双方都在等待,结果是双方线程都不运行,就产生了死锁。