1. 背景
在多线程编程中要用到锁来处理资源的抢占,有可能遇到死锁的情况。
死锁是指两个或两个以上的进程或者线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种 双方都阻塞的现象。
2.模拟一个死锁
示例:两个 lock 对象互相调用导致死锁。
ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();
// 吃饼干
void eating() throws InterruptedException {
String name = Thread.currentThread().getName();
lock1.lock();
System.out.printf("\t\t [Thread: %s] 开始 eating ... \n", name);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock2.lock();
System.out.printf("[Thread: %s] 执行完成 \n", name);
lock1.unlock();
}
// 喝水
void drinking() {
String name = Thread.currentThread().getName();
lock2.lock();
System.out.printf("[Thread: %s] 开始 drinking ... \n", name);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock1.lock();
System.out.printf("[Thread: %s] 执行完成 \n", name);
lock2.unlock();
}
3. 怎么解决?
/**
如果在给定的线程中没有其他线程持有锁,则获取锁
如果锁被另一个线程持有,那么等待锁,直到下面情况发生:
1、当前线程获取的锁;
2、当前线程等待超过指定的等待时间
public boolean tryLock(long timeout, TimeUnit unit)
其中 timeout 是时间,TimeUnit是时间单位(可选分钟,毫秒等)。
4. 示例
即把等待锁的时候的代码改为:
// 带有 超时时间的锁定,当超过指定时间就不在等了
lock2.tryLock(1000, TimeUnit.MILLISECONDS);
完整示例:
class MainApplicatoin {
static class Desk {
ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();
// 吃饼干
void eating() throws InterruptedException {
String name = Thread.currentThread().getName();
lock1.lock();
System.out.printf("\t\t [Thread: %s] 开始 eating ... \n", name);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock2.lock();
// 带有 超时时间的锁定,当超过指定时间就不在等了
// lock2.tryLock(1000, TimeUnit.MILLISECONDS);
System.out.printf("[Thread: %s] 执行完成 \n", name);
lock1.unlock();
}
// 喝水
void drinking() {
String name = Thread.currentThread().getName();
lock2.lock();
System.out.printf("[Thread: %s] 开始 drinking ... \n", name);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock1.lock();
System.out.printf("[Thread: %s] 执行完成 \n", name);
lock2.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
Desk desk = new Desk();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
desk.eating();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.setName("thread1");
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
desk.drinking();
}
});
thread2.setName("thread2");
thread2.start();
// Thread.sleep(60*1000);
}
}
END
网友评论