一、多线程死锁
1、概述
-线程死锁是指两个或两个以上的线程互相持有对方所需要的资源,由于synchronized的特性,一个线程持有一个资源,或者说获得一个锁,在该线程释放这个锁之前,其它线程是获取不到这个锁的,而且会一直死等下去,因此这便造成了死锁
2、死锁产生的原因
- 互斥条件:一个资源,或者说一个锁只能被一个线程所占用,当一个线程首先获取到这个锁之后,在该线程释放这个锁之前,其它线程均是无法获取到这个锁的
- 占有且等待:一个线程已经获取到一个锁,再获取另一个锁的过程中,即使获取不到也不会释放已经获得的锁
- 不可剥夺条件:任何一个线程都无法强制获取别的线程已经占有的锁
- 循环等待条件:线程A拿着线程B的锁,线程B拿着线程A的锁
3、如何避免死锁
- 加锁顺序:线程按照相同的顺序加锁
- 加锁时限,线程获取锁的过程中限制一定的时间,如果给定时间内获取不到,就不要勉强取获得锁
二、死锁代码演示
- 创建一个Mirror类
public class Mirror {
}
- 创建一个Lipstick类
//口红类
public class Lipstick {
}
- 创建一个Makeup类继承Thread类
public class Makeup extends Thread {
//需要的资源只有一份,用static来保证
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
//选择方式
private int choose;
//需要化妆的人
private String name;
public Makeup(int choose, String name) {
this.choose = choose;
this.name = name;
}
@Override
public void run() {
//化妆
try {
makeUp();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//互相持有对方的锁
private void makeUp() throws InterruptedException {
if (choose == 0) {
//获得口红的锁
synchronized (lipstick) {
System.out.println(this.name + "获得口红的锁");
Thread.sleep(1000);
}
//一秒钟后获得镜子的锁
synchronized (mirror) {
System.out.println(this.name + "获得镜子的锁");
}
} else {
//获得镜子的锁
synchronized (mirror) {
System.out.println(this.name + "获得镜子的锁");
Thread.sleep(2000);
}
//两秒钟后获得口红的锁
synchronized (lipstick) {
System.out.println(this.name + "获得口红的锁");
}
}
}
}
- 测试
//死锁:多个线程互相抱着对方需要的资源,然后都不让步,形成死锁
public class DeadTest {
public static void main(String[] args) {
Makeup g1 = new Makeup(0, "白雪公主");
Makeup g2 = new Makeup(1, "灰姑娘");
g1.start();
g2.start();
}
}
- 运行结果
三、Lock锁
- 创建一个Lock类实现Runnable接口
public class Lock implements Runnable{
int tickets=200;
//定义Lock锁:只能锁代码块
private final ReentrantLock lock=new ReentrantLock();
public void run() {
while (true){
try{
lock.lock();
if (tickets>0){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买了第"+tickets--+"张票");
}else {
break;
}
}finally {
//解锁一般在finally中
lock.unlock();
}
}
}
}
- 测试
//测试lock锁
public class LockTest{
public static void main(String[] args) {
Lock lock = new Lock();
new Thread(lock,"线程一").start();
new Thread(lock,"线程二").start();
new Thread(lock,"线程三").start();
}
}
- 运行结果