闽公网安备 35020302035485号
前言:
死锁是多线程编程中常见的问题之一,如果不正确处理,可能会导致程序崩溃或停止响应。为了避免死锁,我们需要了解其根本原因,然后采取相应的措施来解决问题。这包括避免资源分配问题、算法设计问题和代码实现问题等。通过采用上述方法,我们可以有效地减少死锁的风险,并提高多线程应用程序的正确性和可靠性。今天我们就聊聊我们日常写代码时该如何避免死锁的发生。
1、设置超时时间
由于 synchronized不具备尝试锁的能力,可以使用 Lock的tryLock(long timeout, TimeUnit unit) 替代。造成超时的可能性多:发生了死锁、线程陷入死循环、线程执行很慢,无论是哪种情况,只要过了超时时间,就认为失败获取锁失败的时候,要执行一些应对措施:比如打日志、发报警邮件、重启等/**
* 堆代码 duidaima.com
* 使用Lock中的tryLock()避免死锁
*/
publicclass TryLockDeaLock implements Runnable {
int flag = 1;
static Lock lock1 = new ReentrantLock();
static Lock lock2 = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (flag == 1){
try {
if (lock1.tryLock(800, TimeUnit.MILLISECONDS)){
System.out.println("线程1,拿到lock1");
Thread.sleep(new Random().nextInt(1000));
if (lock2.tryLock(800,TimeUnit.MILLISECONDS)){
System.out.println("线程1,成功获取到 lock1 & lock2");
//释放
lock2.unlock();
lock1.unlock();
break;
}else {
System.out.println("线程1,获取lock2,失败,已重试");
lock1.unlock();
Thread.sleep(new Random().nextInt(1000));
}
}else {
System.out.println("线程1,获取lock1,失败,已重试");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (flag ==0){
try {
if (lock2.tryLock(3000, TimeUnit.MILLISECONDS)){
System.out.println("线程2,拿到lock2");
Thread.sleep(new Random().nextInt(1000));
if (lock1.tryLock(3000,TimeUnit.MILLISECONDS)){
System.out.println("线程2,成功获取到 lock1 & lock2");
//释放
lock2.unlock();
lock1.unlock();
break;
}else {
System.out.println("线程2,获取lock1,失败,已重试");
lock1.unlock();
Thread.sleep(new Random().nextInt(1000));
}
}else {
System.out.println("线程2,获取lock2,失败,已重试");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//主函数
public static void main(String[] args) {
TryLockDeaLock t1 = new TryLockDeaLock();
TryLockDeaLock t2 = new TryLockDeaLock();
t1.flag = 1;
t2.flag = 0;
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
}
}
2、多使用并发工具类,而不是自己设计锁ConcurrentHashMap、ConcurrentLinkedQueue、AtomicBoolean等,实际应用中java.util.concurrent.atomic十分有用,简单方便且效率比使用Lock更高,多用并发集合少用同步集合,并发集合比同步集合的可扩展性更好,并发场景需要用到map,首先想到用ConcurrentHashMap。
