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

news2025/2/22 14:51:04

文章目录

      • 死锁
        • 检查是否发生了死锁
        • 死锁的概念
        • 死锁产生的条件
        • 预防死锁
        • 解决死锁
      • 活锁
        • 概念
        • 解决
      • 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锁, 竞争不到返回false
                    System.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();     //休息室1
        Condition condition2 = reentrantLock.newCondition();     //休息室2
        Thread 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.coloradmin.cn/o/1058757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

redis中list类型的操作

一、特点 Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。一个列表最多可以包含 2^32 - 1 个元素 (超过40亿个元素)。 list其底层使用quicklist存储数据 qu…

mysql面试题10:MySQL中有哪几种锁?表级锁、行级锁、页面锁区别和联系?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:Mysql中有哪几种锁? 在MySQL中,主要有以下几种类型的锁: 共享锁(Shared Lock):也称为读锁。多个事务可以同时持有共享锁,可以读取但不能修…

想要精通算法和SQL的成长之路 - 验证二叉树的前序序列化

想要精通算法和SQL的成长之路 - 验证二叉树的前序序列化 前言一. 验证二叉树的前序序列化 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 验证二叉树的前序序列化 原题链接 思路(参考负雪明图): 首先我们看题目所给的字符串&#xff…

Ipython和Jupyter Notebook介绍

Ipython和Jupyter Notebook介绍 Python、IPython和Jupyter Notebook是三个不同但密切相关的工具。简而言之,Python是编程语言本身,IPython是对Python的增强版本,而Jupyter Notebook是一种在Web上进行交互式计算的环境,使用IPytho…

CSS学习小结

css的两种使用方式&#xff1a; ①内嵌样式表 ②导入外部样式表&#xff08;实际开发常用&#xff09;<link href"...." rel"stylesheet"/> 选择器&#xff1a; ①标签选择器&#xff1a;通过标签种类决定 ②类选择器&#xff1a;class"..…

websocket逆向【python实现http/https拦截】

python实现http拦截 前言:为什么要使用http拦截一、技术调研二、技术选择三、使用方法前言:为什么要使用http拦截 大多数爬虫玩家会直接选择API请求数据,但是有的网站需要解决扫码登录、Cookie校验、数字签名等,这种方法实现时间长,难度高。需求里面不需要高并发,有没有…

vertx的学习总结4

一、异步数据和事件流 1.为什么流是事件之上的一个有用的抽象&#xff1f; 2.什么是背压&#xff0c;为什么它是异步生产者和消费者的基础&#xff1f; 3.如何从流解析协议数据&#xff1f; 1. 答&#xff1a;因为它能够将连续的事件序列化并按照顺序进行处理。通过将事件…

ensp桥接电脑网卡

注意&#xff1a; 如果ensp云中没有你想要的网卡&#xff0c;请卸载电脑中的wincap&#xff0c;重新安装wincap即可。 wincap下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1JSXJSu4wKaiCKjGvY0mHKA?pwdh29v 提取码&#xff1a;h29v

【算法训练-数组 三】【结构特性】螺旋矩阵

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是螺旋矩阵&#xff0c;使用【二维数组】这个基本的数据结构来实现 螺旋矩阵【EASY】 二维数组的结构特性入手 题干 解题思路 根据题目示例 mat…

java Spring Boot 自动启动热部署 (别再改点东西就要重启啦)

上文 java Spring Boot 手动启动热部署 我们实现了一个手动热部署的代码 但其实很多人会觉得 这叫说明热开发呀 这么捞 写完还要手动去点一下 很不友好 其实我们开发人员肯定是希望重启这种事不需要自己手动去做 那么 当然可以 我们就让它自己去做 Build Project 这个操作 我们…

10.3运算符重载

#include <iostream>using namespace std;//定义一个复数类 class Complex { private:int real; //实部int vir; //虚部 public:Complex(){}Complex(int r, int v):real(r),vir(v){}void show(){if(vir > 0){cout<<real<<" "<<vir&…

Linux实用操作(固定IP、进程控制、监控、文件解压缩)

目录 一、快捷键 1、ctrl c强制停止 2、ctrl d退出或登出 3、历史命令搜索history 4、光标移动快捷键 5、清屏 二、软件安装 1、CentOS的yum命令 2、Ubantu的apt命令 三、systemctl命令 四、软连接 五、日期、时区 1、date命令 2、修改Linux时区为东八区 3、nt…

Linux基本指令(上)——“Linux”

各位CSDN的uu们好呀&#xff0c;今天&#xff0c;小雅兰的内容是Linux啦&#xff01;&#xff01;&#xff01;主要是Linux的一些基本指令和Linux相关的基本概念&#xff08;系统层面&#xff09;&#xff0c;下面&#xff0c;让我们进入Linux的世界吧&#xff01;&#xff01;…

OpenGLES:绘制一个混色旋转的3D圆锥

一.概述 1.1 对圆锥的拆解 上一篇博文讲解了绘制圆柱体&#xff0c;这一篇讲解绘制一个彩色旋转的圆锥 在绘制圆柱体时提到过&#xff0c;关键点是先将圆柱进行拆解&#xff0c;便于创建出顶点坐标数组 同样&#xff0c;绘制圆锥也先进行拆解 圆锥的拆解很简单&#xff0c…

BGP(Border Gateway Protocol)

目录 BGP报文类型 BGP状态机 BGP邻居 BGP同步规则 Transit AS中的IBGP路由传递 IBGP水平分割原则 路由通告规则 表 计时器 配置命令 维护BGP BGP表 路径属性 WEIGHT LOCAL PREFERENCE AS-path Origin MED NEXT_HOP NEXT_HOP on shared Media COMMUNIT…

Eevee引擎与渲染原理

操作视频&#xff1a; 02-Blender的Eevee渲染器_哔哩哔哩_bilibiliy 技术原理&#xff1a; How 3D Game Rendering Works, A Deeper Dive: Rasterization and Ray Tracing | TechSpot A guide to Blender Eevee render settings - Artisticrender.com 笔记&#xff1a; …

安装Vue脚手架图文详解教程

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 预备工作 在安装Vue脚手架之前&#xff0c;请确保您已经正确安装了npm&#xff1b;假若还尚未安装npm&#xff0c;请你参考 Node.js安装教程图文详解。 安装Vue脚手架 请…

STM32HAL库CRC学习及测试记录

STM32HAL库CRC学习及测试记录 1.CRC的校验原理2.基本原理3.几个基本概念13.1.1 CRC检验码的计算13.1.2 错误检测13.2 STM32中的CRC 4.CRC功能描述5.STM32Cube生成工程6.看官方说如何使用这个驱动程序7.实验现象 1.CRC的校验原理 循环冗余校验(CRC)计算单元是根据固定的生成多项…

实用的嵌入式 C 程序!建议收藏

在学习和工作开发的时候&#xff0c;经常需要使用到各种各样不太常用的操作&#xff0c;这种情况一般是自己手动写一些小程序来处理。因为它们不太常用&#xff0c;所以经常用了又没保存&#xff0c;等到下一次在使用的时候又需要重写&#xff0c;这样的非常浪费时间和精力。 …

力扣练习——链表在线OJ

目录 提示&#xff1a; 一、移除链表元素 题目&#xff1a; 解答&#xff1a; 二、反转链表 题目&#xff1a; 解答&#xff1a; 三、找到链表的中间结点 题目&#xff1a; 解答&#xff1a; 四、合并两个有序链表&#xff08;经典&#xff09; 题目&#xff1a; 解…