死锁
多线程安全问题?
-
多个线程共享相同的数据
-
多个线程同时修改共享数据
解决方案: 同步, 同步方法, 同步代码
带来新的问题:
1) 效率低: 如果多个线程调用同步方法,或者是同步代码块, 只能有一个线程获取对象锁, 才能执行方法,代码块,其他线程在外面阻塞,等到得到对象锁的线程释放这个对象锁, 同步阻塞
2) 同步容易造成死锁
产生死锁的条件:
1> 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2> 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3> 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占用。 线程获取锁对象不是一个
4> 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路 多个线程 获取锁的顺序是刚好反的: 线程1: 获取锁顺序: p1-p2 线程2 获取锁顺序: p2-p1
死锁产生的条件上面4个条件缺一不可的
解决死锁的方案: 只要打破上面4个条件任何一个, 死锁不成立
package com.fs.threadDemo;
/**
* 模拟一个死锁
*/
public class DeadThread {
private Object objA = new Object();// 锁对象
private Object objB = new Object();// 锁对象
private boolean flag = true;// 设置获取锁的顺序: true: objA-objB
// false: objB-objA
public void test(){
if(flag){ //true: objA-objB
synchronized (objA){
System.out.println(Thread.currentThread().getName()+":获取到objA的锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//写在内部, 表示没有释放objA锁, 再去获取objB锁
synchronized (objB){
System.out.println(Thread.currentThread().getName()+":获取到objB的锁");
}
}
//获取objB对象锁, 写在外面,表示先释放objA锁, 再去获取objB锁
/*synchronized (objB){
}*/
}else{//false: objB-objA
synchronized (objB){
System.out.println(Thread.currentThread().getName()+":获取到objB的锁");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (objA){
System.out.println(Thread.currentThread().getName()+":获取到objA的锁");
}
}
}
}
public void changeFlag(boolean flag){
this.flag = flag;
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
//创建DeadThread对象
DeadThread dt = new DeadThread();
//创建两个线程
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
dt.test();
}
},"t1");
//启动线程
t1.start(); //执行 test()
Thread.sleep(100); //让当前线程睡眠, main线程睡眠
//dt.changeFlag(false); //main线程先抢到资源, flag = false;
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
dt.test();
}
},"t2");
//启动线程
t2.start();
}
}
开发过程中,一定避免出现死锁
常用类,集合,IO