在并发编程中,为了保证数据安全性,所以使用锁机制,syn lock cas 等方式保证,但是也从一定程度降低了性能。而除了这个方面,还引入了锁竞争,比如死锁、活锁。
产生死锁的根本原因就是两个以上线程持有A锁的前提下,继续等待B锁。那么如果在获取B锁的时候,获取失败,直接释放原有的A锁,也可以打破这个局面。
/**
* @author qxlx
* @date 2024/1/21 21:07
*/
public class DemoLock {
private Lock lockA = new ReentrantLock();
private Lock lockB = new ReentrantLock();
public void f() {
for ( ;;) {
try {
lockA.lock();
boolean tryLock = lockB.tryLock();
if (tryLock) {
try {
lockB.lock();
// 处理业务逻辑
} finally {
lockB.unlock();
}
}
} finally {
lockA.unlock();
}
}
}
public void g() {
for ( ;;) {
try {
lockB.lock();
boolean tryLock = lockA.tryLock();
if (tryLock) {
try {
lockA.lock();
// 处理业务逻辑
} finally {
lockA.unlock();
}
}
} finally {
lockB.unlock();
}
}
}
}
上面的代码,其实是存在问题的,极端情况下。线程T1 获取lock1锁的时候,尝试获取lock2锁,但是获取lock2锁失败。线程T1释放lock1锁之前,线程T2持有lock2锁,去获取lock1锁失败。如此,就是我尝试获取了,但是失败,一直获取不到自己想要的锁。也释放自己的锁,让对方获取,但是对方获取不到。互相谦让。
一个直白的案例就是:两个人过独木桥,死锁是 你不让,我也不让。大家僵持。
活锁是:你让,我也让,结果都不过桥。
区别:
死锁是两个线程都会阻塞,不会消耗CPU资源,但是活锁却不是,不断的加锁解锁,尝试获取锁失败,解锁。一直占用CPU资源,从而导致一直执行不下去。
那么如何解决呢?
其实办法非常简单,就是在尝试获取锁失败的时候,sleep一会,保证两个线程不是同步操作就可以。
boolean tryLock = lockB.tryLock(r.nextLong() % 10, TimeUnit.MILLISECONDS);