深入学习JUC,深入了解Java线程中死锁与活锁问题,并理解其解决方法,笔记开记!!!

文章目录

      • 死锁
        • 检查是否发生了死锁
        • 死锁的概念
        • 死锁产生的条件
        • 预防死锁
        • 解决死锁
      • 活锁
        • 概念
        • 解决
      • ReentrantLock
        • 概念
        • 可重入
        • 可打断
        • 可超时
        • 可设置公平锁
        • 条件变量

在这里插入图片描述

死锁

检查是否发生了死锁

jstack通过 线程栈快照 定位线程中出现长时间停顿的原因, jconsole 图像界面 检查是否发生了死锁

死锁的概念

多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。
就是两个线程互相占有自己的锁, 却又尝试获取别人的锁, 导致进入死锁状态.

死锁产生的条件
  1. 互斥:

    进程要求对所分配的资源进行排他性控制, 就是一段时间内某资源仅为一个进程所占用

  2. 请求和保持:

    当进程因请求资源而阻塞时, 对已获得的资源保持不放

  3. 不可剥夺:

    进程已经获得的资源在为使用完之前,不能剥夺,只能在使用完由自己释放

  4. 环路等待:

    发生死锁时, 必然存在一个进程–资源的环形链等待链,链中每一个进程已获得的资源同时被下一个进程所请求.

预防死锁
  1. 破坏请求条件:

    资源一次性分配, 这样就不会再有请求了. 但是资源利用率会降低

  2. 破坏请求保持条件:

    进程运行前一次申请它所需要的全部资源, 在它的资源满足前, 不进行运行。一旦运行,资源将不可剥夺.
    这种做法可能严重浪费资源,可能导致饥饿现象.个别线程长时间占用某个资源, 导致该资源的进程迟迟无法运行.

  3. 破坏不可剥夺条件:

    进程申请资源一旦被阻塞, 就必须释放已经占有的所有资源.

  4. 破坏环路等待条件:

    系统给每类资源赋予一个编号, 每一个进程按照编号递增的顺序请求资源, 释放则相反.

解决死锁
  1. 每个线程按照确定的顺序获取锁 , 这样就不会发生一直等待的情况. 但是可能出现饥饿的情况.
  2. 使用tryLock方法固定时长等待锁, 在线程获取锁超时以后, 主动释放之前已经获得的所有锁.

活锁

概念

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

比如一个进程把一个数加到20就退出 , 一个数减到0就退出 ,他们两个一起执行就不会成功.

解决

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

ReentrantLock

概念
  1. 可中断, 其他线程可以把竞争锁的线程打断, 去处理其他逻辑, 防止一直等待
  2. 可设置超时时间, 规定时间内竞争不到锁就放弃, 不像synchroniezd的EntryList一样会一直竞争, 可解决死锁
  3. 可设置公平锁, ReentrantLock默认不公平的,需要自己调用构造方法设置,预防饥饿的情况, 遵循先到先得的原则, 防止线程过多的情况 导致有些锁一直拿不到锁
  4. 可支持多个条件变量, 就是多个类似于synchroniezd一样的waitset. 以后notifyAll的时候可以选择同一个条件的线程一起唤醒.

一般解决饥饿问题不使用公平锁, 会降低并发度, 应该使用tryLock(Time)方法, 一旦获取锁超时就放弃

可重入

同一个线程如果首次获取了这把锁, 那么因为它是这把锁的拥有者, 因此有权利再次获得这把锁.
不可重入的话就会被锁住

public class ReentrantLockTest {private static ReentrantLock reentrantLock=new ReentrantLock();public static void main(String[] args) {reentrantLock.lock();try {System.out.println("进入m1");m1();}finally {reentrantLock.unlock();}}public static void m1(){reentrantLock.lock();try {System.out.println("进入m2");m2();}finally {reentrantLock.unlock();}}public static void m2(){reentrantLock.lock();try {System.out.println("已经在m2");}finally {reentrantLock.unlock();}}
}
可打断
public class ReentrantLockTest {private static ReentrantLock reentrantLock=new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread t1=new Thread(()->{try {reentrantLock.lockInterruptibly();  //此锁可打断 , 如果仅仅是reentrantLock.lock, 则无法打断} catch (InterruptedException e) {e.printStackTrace();System.out.println("锁被打断");return;}System.out.println("竞争锁成功,执行逻辑");});reentrantLock.lock(); //主线程获取锁, t1线程就只能竞争 ,并且设置可打断的竞争t1.start();TimeUnit.SECONDS.sleep(2);  t1.interrupt();       //打断}
}
可超时
public class ReentrantLockTest {private static ReentrantLock reentrantLock=new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread t1=new Thread(()->{try {if (!reentrantLock.tryLock(5,TimeUnit.SECONDS)) { //竞争5s锁, 竞争不到返回falseSystem.out.println("5s了,竞争不到锁,执行其他逻辑");return;}System.out.println("竞争到锁了");} catch (InterruptedException e) {e.printStackTrace();}});reentrantLock.lock(); //主线程获取锁, t1线程就只能竞争t1.start();}
}
可设置公平锁
一般解决饥饿问题不使用公平锁, 会降低并发度, 应该使用tryLock(Time)方法, 一旦获取锁超时就放弃
条件变量
synchronized是所有不满足条件的线程都在一个WaitSet中等待,唤醒时就全部一起唤醒
而ReentrantLock支持多个专门等待不同条件的ConditionObject,类似于waitset,唤醒时按照特定条件的waitset进行唤醒
public class ReentrantLockTest {private static ReentrantLock reentrantLock=new ReentrantLock();public static void main(String[] args) throws InterruptedException {Condition condition1 = reentrantLock.newCondition();     //休息室1Condition condition2 = reentrantLock.newCondition();     //休息室2Thread t1=new Thread(()->{try {condition1.await();     //线程1进入休息室1等待condition1.awaitNanos(10);  //根据纳秒等待condition1.awaitUninterruptibly();  // 可打断的等待condition1.signal();   //唤醒休息室1特定的一个condition1.signalAll();   //唤醒休息室2所有} catch (InterruptedException e) {throw new RuntimeException(e);}});Thread t2=new Thread(()->{try {condition2.await();     //线程2进入休息室2等待} catch (InterruptedException e) {throw new RuntimeException(e);}});}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/124706.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法训练-二分查找 一】【基本二分】二分查找、在排序数组中查找元素的第一个和最后一个位置

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是螺旋矩阵,使用【二维数组】这个基本的数据结构来实现 二分查找【EASY】 从最简单的二分查找入手,进而开始解决一系列其变体…

c语言实现玫瑰花

浅浅跟波风 1.效果图 2.代码实现 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <math.h>const int max_iterations 128; const float stop_threshold 0.01f; const float grad_step 0.01f; const float clip_far 10.0f;const float PI 3.1…

力扣第 365 场周赛虚拟参赛

有序三元组中的最大值 I class Solution { public:long long maximumTripletValue(vector<int>& nums) {vector<long long> num;for (auto &item:nums) {num.push_back(item*1ll);}long long z 0,f 1000000;long long ans 0;long long maxx num[0],mi…

pytest自动化框架运行全局配置文件pytest.ini

还记得在之前的篇章中有讲到Pytest是目前主要流行的自动化框架之一&#xff0c;他有基础的脚本编码规则以及两种运行方式。 pytest的基础编码规则是可以进行修改&#xff0c;这就是今日文章重点。 看到这大家心中是否提出了两个问题&#xff1a;pytest的基础编码规则在哪可以…

【题库】咸鱼之王答题挑战题库大全

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] [{name: , value: 未匹配到内容},# 第一期{name: 《三国演义》中&#xff0c;「大意失街亭」的是马谩&#xff1f;, value: 对},{name: 《三国演义》中&#xff0c;「挥泪斩马谩」的是孙权&#xff1f;, value: 错…

ElementUI之动态树+数据表格+分页

目录 一、动态树 1.1 定义 1.2 导航菜单绑定 1.3 面板内容 1.4 效果展示 二、动态表格 2.1 定义 2.2 搜索框 2.3 数据表格 2.4 分页条 2.5 功能实现 一、动态树 1.1 定义 动态树通常是指在网页或应用程序中创建可展开和折叠的树形结构&#xff0c;其中树的节点是动…

蓝桥杯每日一题2023.10.4

双向排序 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 六十分解法如下&#xff1a;按照题意简单排序 #include<bits/stdc.h> using namespace std; const int N 2e5 10; int n, m, p, q, a[N]; bool cmp(int x, int y) {return x > y; } int main() {cin >&g…

Ubuntu22.04 交叉编译gcc9.5 for arm

一、准备 环境&#xff1a;ubuntu22.04为刚刚安装&#xff0c;未安装gcc等包 vi ~/.bashrc输入 export PATH$PATH:/opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin 保存,reboot 安装&#xff1a; sudo apt install cmake sudo apt install gawk sudo apt instal…

公众号突破2个限制技巧

许多用户在注册公众号时可能会遇到“公众号显示主体已达上限”的问题。这是因为在2018年11月16日对公众号注册数量进行了调整&#xff0c;具体调整如下&#xff1a;1、个人主体注册公众号数量上限从2个调整为1个。2、企业主体注册公众号数量上限从5个调整为2个。这意味着&#…

WebSocket实战之六心跳重连机制

一、前言 WebSocket应用部署到生产环境&#xff0c;我们除了会碰到因为经过代理服务器无法连接的问题&#xff08;注&#xff1a;该问题可以通过搭建WSS来解决&#xff0c;具体配置请看 WebSocket实战之四WSS配置 &#xff09;&#xff0c;另外一个问题就是外网环境不稳定经常…

Windows安装Docker并创建Ubuntu环境及运行神经网络模型

目录 前言在Windows上安装Docker在Docker上创建Ubuntu镜像并运行容器创建Ubuntu镜像配置容器&#xff0c;使其可以在宿主机上显示GUI 创建容器并运行神经网络模型创建容器随便找一个神经网络模型试试 总结 前言 学生党一般用个人电脑玩神经网络&#xff0c;估计很少有自己的服…

linux入门---信号的保存和捕捉

目录标题 信号的一些概念信号的保存pending表block表handler表 信号的捕捉内核态和用户态信号的捕捉 信号的一些概念 1.进程会收到各种各样的信号&#xff0c;那么程序对该信号进行实际处理的动作叫做信号的递达。 2.我们之前说过当进程收到信号的时候可能并不会立即处理这个信…