1. 设置超时时间
使用JUC包中的Lock接口提供的tryLock方法.
该方法在获取锁的时候, 可以设置超时时间, 如果超过了这个时间还没拿到这把锁, 那么就可以做其他的事情, 而不是像 synchronized
如果没有拿到锁会一直等待下去.
boolean tryLock ( long time , TimeUnit unit ) throws InterruptedException ;
造成超时的原因有很多种:发生了死锁, 线程进入了死循环, 线程逻辑复杂执行慢.
到了超时时间, 那么就获取锁失败, 就可以做一些记录操作, 例如 打印错误日志, 发送报警邮件,提示运维人员重启服务等等.
如下的代码演示了 使用tryLock 来避免死锁的案例.
线程1 如果拿到了锁1 , 那么就在指定的800毫秒内去尝试拿到锁2, 如果两把锁都拿到了 , 那么就释放这两把锁. 如果在指定的时间内, 没有拿到锁2 , 那么就释放锁1 .
线程2 与线程1相反, 先去尝试拿到锁2, 如果拿到了, 就去在3s内尝试拿到锁1, 如果拿到了, 那么就释放锁1和2, 如果3s内没有拿到锁1, 那么释放锁2 .
package com . thread . deadlock ; import java . util . Random ; import java . util . concurrent . TimeUnit ; import java . util . concurrent . locks . Lock ; import java . util . concurrent . locks . ReentrantLock ; /**
* 类名称:TryLockDeadlock
* 类描述: 使用lock接口提供的trylock 避免死锁
*
* @author:
* 创建时间:2020/9/12 17:23
* Version 1.0
*/ public class TryLockDeadlock implements Runnable { int flag = 1 ; //ReentrantLock 为可重入锁 static Lock lock1 = new ReentrantLock ( ) ; static Lock lock2 = new ReentrantLock ( ) ; public static void main ( String [ ] args ) { // 创建两个线程 给出不同的flag 并启动 TryLockDeadlock r1 = new TryLockDeadlock ( ) ; TryLockDeadlock r2 = new TryLockDeadlock ( ) ; r1 . flag = 1 ; r2 . flag = 0 ; new Thread ( r1 ) . start ( ) ; new Thread ( r2 ) . start ( ) ; } @Override public void run ( ) { for ( int i = 0 ; i < 100 ; i ++ ) { if ( flag == 1 ) { //先获取锁1 再获取锁2 try { //给锁1 800毫秒与获取锁, 如果拿到锁, 返回true, 反之返回false if ( lock1 . tryLock ( 800 , TimeUnit . MICROSECONDS ) ) { System . out . println ( "线程1获取到了锁1 " ) ; //随机的休眠 Thread . sleep ( new Random ( ) . nextInt ( 1000 ) ) ; if ( lock2 . tryLock ( 800 , TimeUnit . MICROSECONDS ) ) { System . out . println ( "线程1获取到了锁2 " ) ; System . out . println ( " 线程1 成功获取了两把锁 " ) ; //释放两把锁, 退出循环 lock2 . unlock ( ) ; lock1 . unlock ( ) ; break ; } else { System . out . println ( " 线程1尝试获取锁2 失败, 已经重试 " ) ; //释放锁1 lock1 . unlock ( ) ; //随机的休眠 Thread . sleep ( new Random ( ) . nextInt ( 1000 ) ) ; } } else { System . out . println ( " 线程1 获取锁1失败, 已重试 " ) ; } }