什么是活锁和饥饿?

活锁

任务没有被阻塞,由于某些条件没有满足,导致一直重复尝试—失败—尝试—失败的过程。 处于活锁的实体是在不断的改变状态,活锁有可能自行解开。

死锁是大家都拿不到资源都占用着对方的资源,而活锁是拿到资源却又相互释放不执行。

解决活锁的一个简单办法就是在下一次尝试获取资源之前,随机休眠一小段时间。

看一下,我们之前的一个例子,如果最后不进行随机休眠,就会产生活锁,现象就是很长一段时间,两个线程都在不断尝试获取和释放锁。

package constxiong.concurrency.a023;import java.util.Random;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** * 测试 占有部分资源的线程进一步申请其他资源时,如果申请不到,主动释放它占有的资源,破坏 "不可抢占" 条件 * @author ConstXiong * @date 2019-09-24 14:50:51 */public class TestBreakLockOccupation {private static Random r = new Random(); private static Lock lock1 = new ReentrantLock();private static Lock lock2 = new ReentrantLock();public static void main(String[] args) {new Thread(() -> {//标识任务是否完成boolean taskComplete = false;while (!taskComplete) {lock1.lock();System.out.println("线程:" + Thread.currentThread().getName() + " 获取锁 lock1 成功");try {//随机休眠,帮助造成死锁环境try {Thread.sleep(r.nextInt(30));} catch (Exception e) {e.printStackTrace();}//线程 0 尝试获取 lock2if (lock2.tryLock()) {System.out.println("线程:" + Thread.currentThread().getName() + " 获取锁 lock2 成功");try {taskComplete = true;} finally {lock2.unlock();}} else {System.out.println("线程:" + Thread.currentThread().getName() + " 获取锁 lock2 失败");}} finally {lock1.unlock();}//随机休眠,避免出现活锁try {Thread.sleep(r.nextInt(10));} catch (Exception e) {e.printStackTrace();}}}).start();new Thread(() -> {//标识任务是否完成boolean taskComplete = false;while (!taskComplete) {lock2.lock();System.out.println("线程:" + Thread.currentThread().getName() + " 获取锁 lock2 成功");try {//随机休眠,帮助造成死锁环境try {Thread.sleep(r.nextInt(30));} catch (Exception e) {e.printStackTrace();}//线程2 尝试获取锁 lock1if (lock1.tryLock()) {System.out.println("线程:" + Thread.currentThread().getName() + " 获取锁 lock1 成功");try {taskComplete = true;} finally {lock1.unlock();}} else {System.out.println("线程:" + Thread.currentThread().getName() + " 获取锁 lock1 失败");}} finally {lock2.unlock();}//随机休眠,避免出现活锁try {Thread.sleep(r.nextInt(10));} catch (Exception e) {e.printStackTrace();}}}).start();}}

饥饿

一个线程因为 CPU 时间全部被其他线程抢占而得不到 CPU 运行时间,导致线程无法执行。

产生饥饿的原因:

  • 优先级线程吞噬所有的低优先级线程的 CPU 时间
  • 其他线程总是能在它之前持续地对该同步块进行访问,线程被永久堵塞在一个等待进入同步块
  • 其他线程总是抢先被持续地获得唤醒,线程一直在等待被唤醒
package constxiong.concurrency.a024;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * 测试线程饥饿 * @author ConstXiong */public class TestThreadHungry {private static ExecutorService es = Executors.newSingleThreadExecutor();public static void main(String[] args) throws InterruptedException, ExecutionException {Future<String> future1 = es.submit(new Callable<String>() {@Overridepublic String call() throws Exception {System.out.println("提交任务1");Future<String> future2 = es.submit(new Callable<String>() {@Overridepublic String call() throws Exception {System.out.println("提交任务2");return "任务 2 结果";}});return future2.get();}});System.out.println("获取到" + future1.get());}}

打印结果如下,线程池卡死。线程池只能容纳 1 个任务,任务 1 提交任务 2,任务 2 永远得不到执行。

提交任务1

给TA打赏
共{{data.count}}人
人已打赏
Java

为什么要用并发编程?

2020-7-31 0:23:20

Java

synchronized关键字的作用是什么?

2020-7-31 0:26:40

本站所发布的一切源码、模板、应用等文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权。本站内容适用于DMCA政策。若您的权利被侵害,请与我们联系处理,站长 QQ: 84087680 或 点击右侧 私信:盾给网 反馈,我们将尽快处理。
⚠️
本站所发布的一切源码、模板、应用等文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权。本站内容适用于DMCA政策
若您的权利被侵害,请与我们联系处理,站长 QQ: 84087680 或 点击右侧 私信:盾给网 反馈,我们将尽快处理。
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索