#1 设置超时时间
1 )Lock的tryLock(long timeout, TimeUnit unit)
2 )synchronized不具备 尝试拿取 锁的能力
造成超时的可能性多:死锁、线程执行时间长、线程陷入死循环
获取锁失败:打日志、发报警邮件、重启(大事化小)
代码演示:
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @description 用trylock避免死锁
*/
public class TryLockDeadLock implements Runnable {
static Lock lock1 = new ReentrantLock();
static Lock lock2 = new ReentrantLock();
private int flag = 1;
public static void main(String[] args) {
TryLockDeadLock r1 = new TryLockDeadLock();
r1.flag = 1;
TryLockDeadLock r2 = new TryLockDeadLock();
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) {
try {
if (lock1.tryLock(800, TimeUnit.MILLISECONDS)) {
System.out.println("线程1获取到了锁1");
Thread.sleep(new Random().nextInt(1000));
if (lock2.tryLock(800, TimeUnit.MILLISECONDS)) {
System.out.println("线程1获取锁1和锁2");
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失败,已重试");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
if (flag == 0) {
try {
if (lock2.tryLock(3000, TimeUnit.MILLISECONDS)) {
System.out.println("线程2获取到了锁2");
Thread.sleep(new Random().nextInt(1000));
if (lock1.tryLock(3000, TimeUnit.MILLISECONDS)) {
System.out.println("线程2获取锁1和锁2");
lock1.unlock();
lock2.unlock();
break;
} else {
System.out.println("线程2获取锁1失败,释放锁2");
lock2.unlock();
Thread.sleep(new Random().nextInt(1000));
}
} else {
System.out.println("线程2获取锁2失败,已重试");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
2 多使用并发类而不是自己设计锁
1 )ConcurrentHashMap、ConcurrentLinkedQueue、AtomicBoolean
2 )实际应用中java.util.concurrent.atomic使用方便(之前尝试过实现一个使用流的方式
统计读取流写入数据的长度,长度计算使用AtomicLong【因为流可能存在多线程的情
况】),效率比Lock高
代码:
/**
*使用流来统计HTTP协议的Content-Length
*/
publicclassCounterOutputStreamextendsOutputStream{
/**
*流的读写是多线程的
*为了线程安全
*使用Atomic类
*/
private AtomicLong mAtomicLong = new AtomicLong();
/**
*拿到总长度
*@return
*/
publiclongget(){
returnmAtomicLong.get();
}
@Override
publicvoidwrite(inti)throwsIOException{
mAtomicLong.addAndGet(1);
}
publicvoidwrite(longb)throwsIOException{
mAtomicLong.addAndGet(b);
}
@Override
publicvoidwrite(byte[]b)throwsIOException{
mAtomicLong.addAndGet(b.length);
}
@Override
publicvoidwrite(byte[]b,intoff,intlen)throwsIOException{
mAtomicLong.addAndGet(len);
}
@Override
publicvoidflush()throwsIOException{
}
@Override
publicvoidclose()throwsIOException{
super.close();
}
}