【Java开发】JUC进阶 01:Lock锁详解
1 Lock锁介绍
已经在【JUC基础】04简单介绍过了,本文做进一步的拓展,比如公平锁和非公平锁、
📌 明白锁的核心
四个对象:线程,共享资源,锁,锁操作
包括线程如何操作资源,使用锁锁哪个资源,锁让谁等待,谁唤醒,这是我们在加锁时需要考虑的
📌 synchronized 与Lock区别
synchronized是一个关键字,lock是一个类
synchronized自动释放锁,lock需要手动释放
synchronized线程1获得了锁进入阻塞,线程2会死等。lock不会
synchronized非公平,lock可以使用公平锁
synchronized适合锁少量代码同步问题,lock适合锁大量同步代码
📌 Lock重点
Lock接口的实现类均需要主动加锁和解锁:

主要有三个实现类,ReentrantLock最常用:

2 公平锁和非公平锁
📌 要点
公平锁:必须先来后到,十分公平
非公平锁:允许插队(默认-为了效率)
以下是ReentrantLock的构造方式👇(synchronized默认也是非公平锁)

📌 代码举例
首先在主线程中启动一个T线程,给他上锁,休眠2秒(在它释放锁之前,启动一个T1线程,T1线程中创建10个B线程,因为T已经上锁了,那么后边的A线程就必须等T1线程启动后才能获取锁,但是10个B线程已经排在了10个B线程后边),在主线程中再启动10个A线程获取锁,此时可观察公平锁和非公平锁的具体情况。
公平锁:B线程一直再A线程后边
非公平锁:B线程可能会插队到A线程前边
public class testLock {public static void main(String[] args) throws InterruptedException {test1(false);//非公平锁
// test1(true);//公平锁}public static void test1(boolean fair) throws InterruptedException {ReentrantLock lock = new ReentrantLock(fair);new Thread(() -> {lock.lock();try {System.out.println("start");try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {create10T(lock, "B");},"T1").start();System.out.println("end");} finally {lock.unlock();}},"T").start();create10T(lock, "A");}public static void create10T(ReentrantLock lock, String threadPre) {for (int i = 0; i < 10; i++) {Thread thread = new Thread(() -> {lock.lock();try {System.out.println(Thread.currentThread().getName()+"获取到锁!");} finally {lock.unlock();}});thread.setName(threadPre + "-" + i);thread.start();}}
}
非公平锁:

公平锁:

3 Lock版的生产者消费者问题
📌 Condition 通知和唤醒线程
Condition是个接口,基本的方法就是await()和signal()方法;
Conditon中的await()对应Object的wait();
Condition中的signal()对应Object的notify();
Condition中的signalAll()对应Object的notifyAll()。
核心:锁的condition执行await,就是让该线程携带对应的condition进入等待队列,当condition执行signal就是让携带该condition的线程唤醒,使用于lock与unlock之间。
3.1 Lock处理生产者消费者问题
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class LockPC {public static void main(String[] args) {Data data = new Data();new Thread(()->{for (int i = 0; i < 5; i++) {try {data.plus();} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(()->{for (int i = 0; i < 5; i++) {try {data.minus();} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();new Thread(()->{for (int i = 0; i < 5; i++) {try {data.plus();} catch (InterruptedException e) {e.printStackTrace();}}},"C").start();new Thread(()->{for (int i = 0; i < 5; i++) {try {data.minus();} catch (InterruptedException e) {e.printStackTrace();}}},"D").start();}
}class Data{//资源类private int number = 0;Lock lock = new ReentrantLock();Condition condition = lock.newCondition();//+1public void plus() throws InterruptedException {lock.lock();try {while (number!=0){condition.await();//等待}number++;System.out.println(Thread.currentThread().getName()+"=>"+number);condition.signalAll();//通知其他线程,+1结束} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}//-1public void minus() throws InterruptedException {lock.lock();try {while (number==0){condition.await();//等待}number--;System.out.println(Thread.currentThread().getName()+"=>"+number);condition.signalAll();//通知其他线程,-1结束} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}
}
控制台输出:

3.2 Condition 精准通知和唤醒线程
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;//A执行完调用B,B执行完调用C,C执行完调用A
public class LockCondition {public static void main(String[] args) {Data2 data = new Data2();new Thread(()->{for (int i = 0; i < 5; i++) {data.pringtA();}},"A").start();new Thread(()->{for (int i = 0; i < 5; i++) {data.pringtB();}},"B").start();new Thread(()->{for (int i = 0; i < 5; i++) {data.pringtC();}},"C").start();}
}class Data2{private Lock lock= new ReentrantLock();private Condition condition1 = lock.newCondition();private Condition condition2 = lock.newCondition();private Condition condition3 = lock.newCondition();private int number = 1; //1A、2B、3Cpublic void pringtA(){lock.lock();try { //业务,判断->执行->通知while (number!=1){condition1.await();}System.out.println(Thread.currentThread().getName()+"=>"+number);//唤醒指定的Bnumber = 2;condition2.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void pringtB(){lock.lock();try {while (number!=2){condition2.await();}System.out.println(Thread.currentThread().getName()+"=>"+number);//唤醒指定的Bnumber = 3;condition3.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void pringtC(){lock.lock();try {while (number!=3){condition3.await();}System.out.println(Thread.currentThread().getName()+"=>"+number);//唤醒指定的Bnumber = 1;condition1.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}
}
控制台输出:

相关文章:

【Java开发】JUC进阶 01:Lock锁详解
1 Lock锁介绍已经在【JUC基础】04简单介绍过了,本文做进一步的拓展,比如公平锁和非公平锁、📌 明白锁的核心四个对象:线程,共享资源,锁,锁操作包括线程如何操作资源,使用锁锁哪个资源…...

关于登录校验的解决方案以及原理(回顾知识点)--项目开发那点事(自问自答版本)
开始前奏: 嘻嘻😄 通常一个完整的系统,需要安全性的保证。如登录校验,登录成功后,才可以访问服务资源。在服务端渲染项目中,我们通常使用 session来进行登录校验。在前后端分离的场景中,很多时…...

【数据结构】邻接矩阵和邻接图的遍历
写在前面 本篇文章开始学习数据结构的图的相关知识,涉及的基本概念还是很多的。本文的行文思路:学习图的基本概念学习图的存储结构——本文主要介绍邻接矩阵和邻接表对每种结构进行深度优先遍历和广度优先遍历先识概念话不多说,狠活献上学习思想等等&…...

设计跳表(动态设置节点高度)
最近学习redis的zset时候,又看到跳表的思想,突然对跳表的设置有了新的思考 这是19年设计的跳表,在leetcode的执行时间是200ms 现在我对跳表有了新的想法 1、跳表的设计,类似二分查找,但是不是二分查找,比较…...

基于神经辐射场(Neural Radiance Fileds, NeRF)的三维重建- 简介(1)
Nerf简介 Nerf(neural Radiance Fileds) 为2020年ICCV上提出的一个基于隐式表达的三维重建方法,使用2D的 Posed Imageds 来生成(表达)复杂的三维场景。现在越来越多的研究人员开始关注这个潜力巨大的领域,也…...

【AI面试】NMS 与 Soft NMS 的辨析
往期文章: AI/CV面试,直达目录汇总【AI面试】L1 loss、L2 loss和Smooth L1 Loss,L1正则化和L2正则化 一、NMS 非极大值抑制(Non-Maximum Suppression,NMS),并不是深度学习时期,目标…...

一文让你彻底理解Linux内核多线程(互斥锁、条件变量、读写锁、自旋锁、信号量)
一、互斥锁(同步) 在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源。这个过程有点类似于,公司部门里,我在使用着打印机打印东西的同时(还没有打印完),别人刚好也在…...

利用python写一个gui小公举--环境搭建
文章目录背景搭建环境安装必要库添加工具快捷方式检验背景 在实习过程中遇到一个问题,某项目是通过python代码实现的,而且需要一直修改参数实现功能,过程有些繁琐。虽然师兄用PHP study搭了一个网站用于查看结果,但是还是过于繁琐…...

英飞凌Tricore实战系列02_ENDINIT属性看门狗原理及应用
目录 1.概述2.ENDINIT功能及使用2.1 ENDINIT属性2.2 改写受ENDINIT保护寄存器的步骤3. Tricore 看门狗介绍及使用3.1 看门狗系统介绍3.1.1 安全看门狗介绍3.1.2 CPU看门狗介绍3.2 看门狗模式介绍3.2.1 Time-out模式3.2.2 正常模式(Normal Mode)3.2.3 禁用模式(Disabled Mode…...

Java Number类
Java Number 类是一个抽象类,它是所有数字类的基类。Java 中的数字类包括 Byte、Short、Integer、Long、Float 和 Double,它们都继承自 Number 类。Java Number 类提供了一些常用的方法,可以用于将数字类型转换为不同的格式,以及进…...

C++构造和析构
欢迎来观看温柔了岁月.c的博客 目前 设有C学习专栏 C语言项目专栏 数据结构与算法专栏 目前主要更新C学习专栏,C语言项目专栏不定时更新 待C专栏完毕,会陆续更新C项目专栏和数据结构与算法专栏 一周主要三更,星期三,星期五&#x…...

docker安装即docker连接mysql(window)
一 安装docker 1.什么是docker Docker容器与虚拟机类似,但二者在原理上不同。容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件,因此容器更具有便携性、高效地利用服务器。 2.WSL2 WSL,即Windows Subsystem on Linux,中…...

HMM-维特比算法
HMM-维特比算法(viterbi)HMM回顾隐马科夫链解法:维特比算法(Viterbi)HMM回顾 最终的公式可以解释主要分为两个部分: P(xi|yi),发射概率,字面意思是从一个词性中发射/生成出某一个单…...

【C++初阶】2. 类和对象_1
1. 面向过程和面向对象的初步认识 2. 类的引入 C语言结构体中只能定义变量,在C中,结构体内不仅可以定义变量,也可以定义函数。比如: 之前在数据结构初阶中,用C语言方式实现的栈,结构体中只能定义变量&#…...

kotlin把函数作为参数转递给另一个函数
kotlin把函数作为参数转递给另一个函数 fun say(s: String, foo: (String) -> Unit) {print("hello")foo(s) }fun hi(str: String) {println(str) }fun main(args: Array<String>) {say("hello", ::hi) } 输出: hellohello...

海思嵌入式开发-005-OpenHarmony源码编译问题
海思嵌入式开发-005-OpenHarmony源码编译问题一、问题描述二、解决方案2.1解决原理2.2获取OpenHarmony 3.1.1 Release源码2.3最后解决问题,编译成功。一、问题描述 按照链接拉取master源码,出现如下问题,打开build.log文件 提示相应位置的文…...

指针的进阶续(笔试题强化练习)
写在前面:在上次我们学习了指针的相关类型的知识,对指针家族的成员基本有了了解,这次让我们跟着一些题目来练习和补充一些知识,这有助于我们强化理解这些知识。 话不多说,我们马上开始: 1.指针和数组的笔…...

一个供参考的计算机的学习路线
本文是介绍如何成为一个Geek,一个真正的计算机高手。 适合有成为IT领域技术大牛的人参考。 写给大一新生和所有向深耕IT领域的人,避免走一些弯路。 仅代表个人想法,供批判性参考。 第一门入门的必备功课-语法与算法 什么是计算机?…...

React(五):受控组件、高阶组件、Portals、Fragment、CSS的编写方式
React(五)一、受控组件1.什么是受控组件(v-model)2.收集表单数据:input和单选框3.收集表单数据:下拉框二、非受控组件三、高阶组件1.什么是高阶组件2.高阶组件的应用13.高阶组件的应用2-注入Context4.高阶组件的应用3-登录鉴权5.高…...

MATLAB——系统环境
MATLAB概述MATLAB的发展MATLAB:MATrix LABoratory1980年前后,Cleve Moler教授编写的Linpack 和Eispack的接口程序。1984年,MATLAB第1版(DOS版)1992年,MATLAB4.0版1994年,MATLAB 4.2版1997年,MATLAB 5.0版1999年&#x…...

2 GateWay工作流程+GateWay搭建
GateWay工作流程GateWay搭建 核心流程图如下: 核心概念: 客户端向 Spring Cloud Gateway 发出请求。如果Gateway Handler Mapping确定请求与路由匹配,则将其发送到Gateway Web Handler 处理程序。此处理程序通过特定于请求的Fliter链运行请求…...

【微信小程序】富文本rich-text的图片预览效果的几种方法
前言 使用原生小程序开发,实现在富文本rich-text中的图片预览效果的几种方法对比。 1.正则wx.previewImage(有明显不足) 一个不需要用额外组件或插件的方法: 思路:使用正则把图片的url进行剖离出来,push…...

通信网络-Socket、Java中的网络支持、多线程服务器
前言 通信网络-Socket、Java中的网络支持、多线程服务器 场景:使用java网络创建一个聊天室 博客地址:芒果橙的个人博客 文章目录前言通信网络-SocketTCP/IPTCP/IP 模型端口Java中的网络支持概念1. InetAddress2. URL3. Socket4. Datagram多线程服务器应用…...

搞懂 JS this、call、apply、bind
搞懂 JS this、call、apply、bind javascript 的 this ECMAScript 规范中这样写: this 关键字执行为当前执行环境的 ThisBinding。 MDN 上这样写: In most cases, the value of this is determined by how a function is called. 在绝大多数情况下&…...

力扣209长度最小的子数组
209. 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。 示例 1…...

【mysql是怎样运行的】-InnoDB数据页结构
文章目录1. 数据库的存储结构:页1.1 磁盘与内存交互基本单位:页1.2 页结构概述1.3 页的上层结构2. 页的内部结构2.1 第1部分:文件头部和文件尾部2.1.1 File Header(文件头部)(38字节)2.1.2 File…...

VIM实用指南(10)语法自动补全插件coc.nvim
最近发现了一个新的自动补全插件coc.nvim异步,nodejs后端,配合它自身的lsp支持用起来非常舒服,同样也支持lsp和snippets,强烈推荐,值得一试。 1、使用vimplug安装插件 1.进入coc.nvim 在github的主页https://github.…...

【Vue3 第二十二章】过渡动画
一、基本用法 <Transition> 是一个内置组件,这意味着它在任意别的组件中都可以被使用,无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发: 由 v-if 所触发的切换由 v-…...

【linux】:进程状态(僵尸进程等)以及环境变量
文章目录 前言一.进程状态 进程的优先级二.环境变量总结前言 本篇文章是接着上一篇【linux】:进程概念的后续,对于有基础的同学可以直接看这篇文章,对于初学者来说强烈建议大家从上一篇的概念开始看起,上一篇主要解释了冯诺依曼体系以及操…...

【C语言——练习题】指针,你真的学会了吗?
✨✨✨✨如果文章对你有帮助记得点赞收藏关注哦!!✨✨✨✨ 文章目录✨✨✨✨如果文章对你有帮助记得点赞收藏关注哦!!✨✨✨✨一维数组练习题:字符数组练习题:字符指针练习题:二维数组练习题&am…...