活锁
作者:互联网
目录
1、活锁的概念
概念与定义:是指两个或两个以上的进程(或线程)在执行过程中,因不断地尝试性获取资源而造成的一种无限循环的现象。
2、活锁代码示例
2.1 代码示例
package com.autocoding.lock.livelock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import lombok.extern.slf4j.Slf4j;
/**
*
* 场景:
* <p> t1线程先尝试获取lock1,再尝试获取lock2,如果获取lock2失败,则释放lock1,再进行重试 </p>
* <p> t2线程先尝试获取lock2,再尝试获取lock1,如果获取lock1失败,则释放lock2,再进行重试 </p>
* 这种场景是会出现活锁现象的
*/
@Slf4j
public class LiveLockTest {
public static void main(String[] args) throws InterruptedException {
final Lock lock1 = new ReentrantLock();
final Lock lock2 = new ReentrantLock();
final Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
final AtomicInteger counter = new AtomicInteger();
while (true) {
if (lock1.tryLock()) {
try {
LiveLockTest.log.info("获取了lock1,准备获取lock2.....");
//为了模拟两个线程相互持有对方需要的锁,这里休眠一下
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (lock2.tryLock()) {
try {
LiveLockTest.log.info("获取了lock2");
LiveLockTest.log.error("经过{}次重试之后,获取了两把锁,业务逻辑处理", counter);
break;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
counter.incrementAndGet();
}
}
});
thread1.setName("线程1");
final Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
final AtomicInteger counter = new AtomicInteger();
while (true) {
if (lock2.tryLock()) {
try {
LiveLockTest.log.info("获取了lock2,准备获取lock1.....");
//为了模拟两个线程相互持有对方需要的锁,这里休眠一下
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (lock1.tryLock()) {
try {
LiveLockTest.log.info("获取了lock1");
LiveLockTest.log.error("经过{}次重试之后,获取了两把锁,业务逻辑处理", counter);
break;
} finally {
lock1.unlock();
}
}
} finally {
lock2.unlock();
}
}
counter.incrementAndGet();
}
}
});
thread2.setName("线程2");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
2.2 程序运行结果
经过大量的重试时间,最终两个线程都可以获取锁,继续执行,但是大部分情况是,每次重试都是无效的重试,进行自旋,浪费cpu宝贵的执行时间。
2021-04-11 17:07:25.985 [线程1] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock1,准备获取lock2.....
2021-04-11 17:07:25.985 [线程2] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock2,准备获取lock1.....
2021-04-11 17:07:25.990 [线程2] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock2,准备获取lock1.....
2021-04-11 17:07:25.990 [线程1] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock1,准备获取lock2.....
2021-04-11 17:07:25.992 [线程1] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock1,准备获取lock2.....
2021-04-11 17:07:25.992 [线程2] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock2,准备获取lock1.....
2021-04-11 17:07:25.994 [线程2] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock2,准备获取lock1.....
2021-04-11 17:07:25.994 [线程1] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock1,准备获取lock2.....
2021-04-11 17:07:25.996 [线程2] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock2,准备获取lock1.....
2021-04-11 17:07:25.996 [线程1] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock1,准备获取lock2.....
2021-04-11 17:07:25.998 [线程1] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock2
2021-04-11 17:07:25.998 [线程1] ERROR com.autocoding.lock.livelock.LiveLockTest - 经过4次重试之后,获取了两把锁,业务逻辑处理
2021-04-11 17:07:25.999 [线程2] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock2,准备获取lock1.....
2021-04-11 17:07:26.001 [线程2] INFO com.autocoding.lock.livelock.LiveLockTest - 获取了lock1
2021-04-11 17:07:26.001 [线程2] ERROR com.autocoding.lock.livelock.LiveLockTest - 经过25620次重试之后,获取了两把锁,业务逻辑处理
3、解决活锁的两种方案
3.1 重试时休眠一个随机时间再进行重试
package com.autocoding.lock.livelock;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import lombok.extern.slf4j.Slf4j;
/**
*
* 场景:
* <p> t1线程先尝试获取lock1,再尝试获取lock2,如果获取lock2失败,则释放lock1,再进行重试 </p>
* <p> t2线程先尝试获取lock2,再尝试获取lock1,如果获取lock1失败,则释放lock2,再进行重试 </p>
* 这种场景是会出现活锁现象的
* <p>解决方案1</p>
* 加入一些随机因素,再次竞争资源时,重试时间间隔加入一些随机时间
*/
@Slf4j
public class Solve1LiveLockTest {
public static void main(String[] args) throws InterruptedException {
final Lock lock1 = new ReentrantLock();
final Lock lock2 = new ReentrantLock();
final Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (lock1.tryLock()) {
try {
Solve1LiveLockTest.log.info("获取了lock1,准备获取lock2.....");
//为了模拟两个线程相互持有对方需要的锁,这里休眠一下
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (lock2.tryLock()) {
try {
Solve1LiveLockTest.log.info("获取了lock2");
Solve1LiveLockTest.log.info("业务逻辑处理");
break;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
// 加入一些随机因素,再次竞争资源时,重试时间间隔加入一些随机时间
try {
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(10));
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
thread1.setName("线程1");
final Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (lock2.tryLock()) {
try {
Solve1LiveLockTest.log.info("获取了lock2,准备获取lock1.....");
//为了模拟两个线程相互持有对方需要的锁,这里休眠一下
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (lock1.tryLock()) {
try {
Solve1LiveLockTest.log.info("获取了lock1");
Solve1LiveLockTest.log.info("业务逻辑处理");
break;
} finally {
lock1.unlock();
}
}
} finally {
lock2.unlock();
}
}
// 加入一些随机因素,再次竞争资源时,重试时间间隔加入一些随机时间
try {
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(10));
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
thread2.setName("线程2");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
程序运行结果:
2021-04-11 17:09:10.895 [线程1] INFO com.autocoding.lock.livelock.Solve1LiveLockTest - 获取了lock1,准备获取lock2.....
2021-04-11 17:09:10.895 [线程2] INFO com.autocoding.lock.livelock.Solve1LiveLockTest - 获取了lock2,准备获取lock1.....
2021-04-11 17:09:10.899 [线程1] INFO com.autocoding.lock.livelock.Solve1LiveLockTest - 获取了lock2
2021-04-11 17:09:10.899 [线程1] INFO com.autocoding.lock.livelock.Solve1LiveLockTest - 业务逻辑处理
2021-04-11 17:09:10.909 [线程2] INFO com.autocoding.lock.livelock.Solve1LiveLockTest - 获取了lock2,准备获取lock1.....
2021-04-11 17:09:10.911 [线程2] INFO com.autocoding.lock.livelock.Solve1LiveLockTest - 获取了lock1
2021-04-11 17:09:10.911 [线程2] INFO com.autocoding.lock.livelock.Solve1LiveLockTest - 业务逻辑处理
3.2 严格控制获取资源的顺序
package com.autocoding.lock.livelock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import lombok.extern.slf4j.Slf4j;
/**
*
* 场景:
* <p> t1线程先尝试获取lock1,再尝试获取lock2,如果获取lock2失败,则释放lock1,再进行重试 </p>
* <p> t2线程先尝试获取lock2,再尝试获取lock1,如果获取lock1失败,则释放lock2,再进行重试 </p>
* 这种场景是会出现活锁现象的
* <p>解决方案2</p>
* 严格控制获取资源的顺序,所有的线程,都是先获取lock1,再获取lock2
*/
@Slf4j
public class Solve2LiveLockTest {
public static void main(String[] args) throws InterruptedException {
final Lock lock1 = new ReentrantLock();
final Lock lock2 = new ReentrantLock();
final Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (lock1.tryLock()) {
try {
Solve2LiveLockTest.log.info("获取了lock1,准备获取lock2.....");
//为了模拟两个线程相互持有对方需要的锁,这里休眠一下
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (lock2.tryLock()) {
try {
Solve2LiveLockTest.log.info("获取了lock2");
Solve2LiveLockTest.log.info("业务逻辑处理");
break;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
}
}
});
thread1.setName("线程1");
final Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (lock1.tryLock()) {
try {
Solve2LiveLockTest.log.info("获取了lock1,准备获取lock2.....");
//为了模拟两个线程相互持有对方需要的锁,这里休眠一下
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (final InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (lock2.tryLock()) {
try {
Solve2LiveLockTest.log.info("获取了lock2");
Solve2LiveLockTest.log.info("业务逻辑处理");
break;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
}
}
});
thread2.setName("线程2");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
程序运行结果:
2021-04-11 17:09:43.755 [线程2] INFO com.autocoding.lock.livelock.Solve2LiveLockTest - 获取了lock1,准备获取lock2.....
2021-04-11 17:09:43.759 [线程2] INFO com.autocoding.lock.livelock.Solve2LiveLockTest - 获取了lock2
2021-04-11 17:09:43.759 [线程2] INFO com.autocoding.lock.livelock.Solve2LiveLockTest - 业务逻辑处理
2021-04-11 17:09:43.759 [线程1] INFO com.autocoding.lock.livelock.Solve2LiveLockTest - 获取了lock1,准备获取lock2.....
2021-04-11 17:09:43.761 [线程1] INFO com.autocoding.lock.livelock.Solve2LiveLockTest - 获取了lock2
2021-04-11 17:09:43.761 [线程1] INFO com.autocoding.lock.livelock.Solve2LiveLockTest - 业务逻辑处理
标签:lock,lock2,获取,活锁,lock1,线程,com 来源: https://blog.csdn.net/s2008100262/article/details/115602212