引言:
java开发中当某些逻辑设计得不合理时,将会出现“线程死锁”的问题。
线程死锁
- 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
- 出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续。当我们使用Java中的同步机制时要避免出现死锁。
线程死锁演示 1:
public class DeadLockTest {
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer();
StringBuffer s2 = new StringBuffer();
new Thread() {
@Override
public void run() {
synchronized (s1) {
s1.append("a");
s2.append("1");
try {
sleep(1000);//强行休眠,提高出现死锁的概率,达到演示效果
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s2) {
s1.append("b");
s2.append("2");
System.out.println(s1);
System.out.println(s2);
}
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (s2) {
s1.append("c");
s2.append("3");
try {
Thread.sleep(1000);//强行睡眠,提高出现死锁的概率,达到演示效果
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s1) {
s1.append("d");
s2.append("4");
System.out.println(s1);
System.out.println(s2);
}
}
}
}).start();
}
}
第一个线程握住s1锁,等待其他线程释放s2锁;第二个线程握住s2锁,等待其他线程释放s1锁。两个线程都在等待对方放弃自己需要的同步资源,出现死锁。
线程死锁演示 2:
class A {
public synchronized void foo(B b) {//非静态方法同步监视器为this:A类的对象a
System.out.println("当前线程名:" + Thread.currentThread().getName() + " 进入了A实例的foo()方法");
try {
Thread.sleep(1000);//强行休眠,提高出现死锁的概率,达到演示效果
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前线程名:" + Thread.currentThread().getName() + " 企图调用B实例的last()方法");
b.last();
}
public synchronized void last() {//非静态方法同步监视器为this:A类的对象a
System.out.println("进入了A类的last()方法内部");
}
}
class B {
public synchronized void bar(A a) {//非静态方法同步监视器为this:B类的对象b
System.out.println("当前线程名:" + Thread.currentThread().getName() + " 进入了B实例的bar()方法");
try {
Thread.sleep(1000);//强行休眠,提高出现死锁的概率,达到演示效果
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前线程名:" + Thread.currentThread().getName() + " 企图调用A实例的last()方法");
a.last();
}
public synchronized void last() {//非静态方法同步监视器为this:B类的对象b
System.out.println("进入了B类的last()方法内部");
}
}
class DeadLock implements Runnable {
A a = new A();
B b = new B();
public void init() {
Thread.currentThread().setName("主线程");
a.foo(b);//调用a对象的foo()方法
System.out.println("主线程结束");
}
@Override
public void run() {
Thread.currentThread().setName("副线程");
b.bar(a);//调用b对象的bar()方法
System.out.println("副线程结束");
}
}
public class DeadLockTest {
public static void main(String[] args) {
DeadLock dl = new DeadLock();
new Thread(dl).start();
dl.init();
}
}
减少死锁的出现,自己体会
class A {
public synchronized void foo(B b) {//非静态方法同步监视器为this:A类的对象a
System.out.println("当前线程名:" + Thread.currentThread().getName() + " 进入了A实例的foo()方法");
System.out.println("当前线程名:" + Thread.currentThread().getName() + " 企图调用B实例的last()方法");
b.last();
}
public synchronized void last() {//非静态方法同步监视器为this:A类的对象a
System.out.println("进入了A类的last()方法内部");
}
}
class B {
public synchronized void bar(A a) {//非静态方法同步监视器为this:B类的对象b
System.out.println("当前线程名:" + Thread.currentThread().getName() + " 进入了B实例的bar()方法");
System.out.println("当前线程名:" + Thread.currentThread().getName() + " 企图调用A实例的last()方法");
a.last();
}
public synchronized void last() {//非静态方法同步监视器为this:B类的对象b
System.out.println("进入了B类的last()方法内部");
}
}
class DeadLock implements Runnable {
A a = new A();
B b = new B();
public void init() {
Thread.currentThread().setName("主线程");
//调用a对象的foo()方法
a.foo(b);
System.out.println("主线程结束");
}
@Override
public void run() {
Thread.currentThread().setName("副线程");
//调用b对象的bar()方法
b.bar(a);
System.out.println("副线程结束");
}
}
public class DeadLockTest {
public static void main(String[] args) {
DeadLock dl = new DeadLock();
new Thread(dl).start();
//增加"不出现死锁"的概率
try {
Thread.sleep(1000);//主线程休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
dl.init();
}
}
//可能的输出
/**
当前线程名:副线程 进入了B实例的bar()方法
当前线程名:副线程 企图调用A实例的last()方法
进入了A类的last()方法内部
副线程结束
当前线程名:主线程 进入了A实例的foo()方法
当前线程名:主线程 企图调用B实例的last()方法
进入了B类的last()方法内部
主线程结束
**/
解决办法
- 专门的算法、原则
- 尽量减少同步资源的定义
- 尽量避免嵌套同步