活锁

2021/4/11 18:31:24

本文主要是介绍活锁,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录

1、活锁的概念

2、活锁代码示例

2.1 代码示例

2.2 程序运行结果

3、解决活锁的两种方案

3.1 重试时休眠一个随机时间再进行重试

3.2 严格控制获取资源的顺序


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 - 业务逻辑处理

 



这篇关于活锁的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程