锁(Locks)

article/2025/9/20 13:17:20

锁(Locks)

1 ReentrantLock

应用demo

可重入锁,是一种使用递归无堵塞的同步机制

synchronized 更强大、更灵活的锁机制,可以减少死锁发生的概率

默认为非公平锁,可以自定义为公平锁

底层采用 AQS 实现,通过内部 Sync 集成 AQS

简单应用:

/*** @author kenewstar* @version 1.0* @date 2021/5/14*/
public class Concurrent07 {private int count;private final Lock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {Concurrent07 c = new Concurrent07();CountDownLatch count = new CountDownLatch(2);ExecutorService service = Executors.newCachedThreadPool();service.execute(() -> {// 加锁c.lock.lock();try {for (int i = 0; i < 100000000; i++) {c.count ++;}count.countDown();} finally {// 释放锁c.lock.unlock();}});service.execute(() -> {c.lock.lock();try {for (int i = 0; i < 100000000; i++) {c.count ++;}count.countDown();} finally {c.lock.unlock();}});count.await();service.shutdown();System.out.println("计算结果:" + c.count);}}

运行结果:

在这里插入图片描述

如果不对两个线程进行加锁操作,那么最终结果将不是预期的。

公平锁与非公平锁

公平锁的简单应用

/*** @author kenewstar* @version 1.0* @date 2021/5/15*/
public class Concurrent08 {/*** 公平锁,fair参数设置为true* 非公平锁,fair参数设置为false(默认)*/private static final Lock lock = new ReentrantLock(true);public static void runTest(String name, int time) {lock.lock();try {System.out.println("线程 " + name + "获取了锁");TimeUnit.SECONDS.sleep(time);} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();System.out.println("线程 " + name + "释放了锁");}}public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 2; i++) {executorService.execute(() -> runTest("A", 1));executorService.execute(() -> runTest("B", 1));executorService.execute(() -> runTest("C", 1));}executorService.shutdown();}
}

运行结果:

在这里插入图片描述

第二次获取锁的顺序和第一次一致,也就是等待锁的时间最长的优先获取锁。

非公平锁的结果可能如下(也可能与公平锁一致,具有不确定性):

在这里插入图片描述

响应中断

我们创建两个线程造成死锁,然后使用其中一个线程中断,然后另一个线程就可以正常获取锁了。

案例如下:

/*** @author kenewstar* @version 1.0* @date 2021/5/15*/
public class Concurrent09 {private static Lock lock1 = new ReentrantLock();private static Lock lock2 = new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {try {lock1.lockInterruptibly();System.out.println("t1 获取了 lock1");lock2.lockInterruptibly();System.out.println("t1 获取了 lock2");TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();} finally {lock1.unlock();lock2.unlock();}});Thread t2 = new Thread(() -> {try {lock2.lockInterruptibly();System.out.println("t2 获取了 lock2");lock1.lockInterruptibly();System.out.println("t2 获取了 lock1");TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();} finally {lock2.unlock();lock1.unlock();}});t1.start();t2.start();Thread.sleep(2000);t1.interrupt();}
}

运行结果:

在这里插入图片描述

两个线程都在相互等待对方释放锁导致死锁,此时 t1 线程中断,然后t1线程中的lock1释放锁,t2线程就能成功获取到t1锁了。

限时等待

/*** @author kenewstar* @version 1.0* @date 2021/5/15*/
public class Concurrent10 {private static Lock lock = new ReentrantLock();public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();executorService.execute(() -> {boolean flag = false;try {flag = lock.tryLock(1000, TimeUnit.MILLISECONDS);if (flag) {System.out.println("线程A获取锁成功");TimeUnit.SECONDS.sleep(2);} else {System.out.println("线程A获取锁失败");}} catch (InterruptedException e) {e.printStackTrace();} finally {if (flag) {lock.unlock();}}});executorService.execute(() -> {boolean flag = false;try {flag = lock.tryLock(1000, TimeUnit.MILLISECONDS);if (flag) {System.out.println("线程B获取锁成功");TimeUnit.SECONDS.sleep(2);} else {System.out.println("线程B获取锁失败");}} catch (InterruptedException e) {e.printStackTrace();} finally {// ReentrantLock的一个方法:isHeldByCurrentThread()// 可用于判断当前线程是否获取到Lock锁if (flag) {lock.unlock();}}});executorService.shutdown();}
}

运行结果:

在这里插入图片描述

线程B会尝试 1s 后打印获取锁失败信息。

ReentrantLock与Synchronized

synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。

synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。

synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以响应中断。

相比于synchronized,ReentrantLock 在功能上更加丰富,它具有 可重入、可中断、可限时、公平锁 等特点

2 ReentrantReadWriteLock

上一节我们使用了ReentrantLock锁,该锁效果与synchronized的关键字的功能差不多,如果在写多读少的环境下,毋庸置疑的使用它也是比较合适的,但是在写少读多的环境下进行加锁,势必造成不必要的性能浪费。在只读的情况下并不存在线程安全问题,其他线程也可读取,但是此时加上了互斥锁,那么会大大降低性能,因此我们需要一个能够在读线程的情况下,其他线程也可以获取锁。我们可以使用ReentrantReadWriteLock。

读写锁,两把锁:共享锁-读锁,排它锁:写锁

支持公平性、非公平性、可重入、锁降级

锁降级:遵循获取写锁、获取读锁在释放写锁的次序,写锁能够降级成为读锁

读写锁的应用

简单应用如下:

/*** @author kenewstar* @version 1.0* @date 2021/5/16*/
public class Concurrent11 {private static ReadWriteLock lock = new ReentrantReadWriteLock();private static Lock readLock =  lock.readLock();private static Lock writeLock = lock.writeLock();private static Random rand = new Random(100);private static int pc;public void read() {readLock.lock();try {System.out.println("线程 " + Thread.currentThread() + " 读取数据 ----> " + pc);TimeUnit.MILLISECONDS.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {readLock.unlock();}}public void write(String name) {writeLock.lock();try {int s = rand.nextInt(99);System.out.println("线程" + name + " 写入数据 ---> " + s);pc = s;} finally {writeLock.unlock();}}public static void main(String[] args) {Concurrent11 c = new Concurrent11();ExecutorService service = Executors.newFixedThreadPool(20);for (int i = 0; i < 10; i++) {service.execute(c::read);}service.execute(() -> c.write("E"));service.execute(() -> c.write("D"));service.shutdown();}}

运行结果如下:

在这里插入图片描述

运行过程,前面十个线程是几乎同时打印数据,然后等待大约 1s 后面两个线程才开始打印数据。由此可知,读取数据时,其他读取线程也可以获取读锁,而无法获取写锁。写数据时,读写锁都无法获取,即读锁是共享锁,写锁是排它锁。

锁降级

即是由写锁降级为读锁

/*** @author kenewstar* @version 1.0* @date 2021/5/16*/
public class Concurrent12 {private static ReadWriteLock lock = new ReentrantReadWriteLock();private static Lock readLock = lock.readLock();private static Lock writeLock = lock.writeLock();private int num;public static void main(String[] args) {Concurrent12 c = new Concurrent12();ExecutorService service = Executors.newFixedThreadPool(10);for (int i = 0; i < 5; i++) {service.execute(c::read);}service.execute(c::write);for (int i = 0; i < 8; i++) {service.execute(c::read);}service.shutdown();}public void read() {readLock.lock();try {System.out.println(Thread.currentThread() + " 读取 ---> " + num);Thread.sleep(800);} catch (InterruptedException e) {e.printStackTrace();} finally {readLock.unlock();}}public void write() {writeLock.lock();try {num = 12;Thread.sleep(600);} catch (Exception e) {e.printStackTrace();}readLock.lock();try {writeLock.unlock();System.out.println(Thread.currentThread() + " 锁降级 ---> " + num);Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();} finally {readLock.unlock();}}
}

运行结果如下:

在这里插入图片描述

首先获取读锁,此时无法获取写锁,等待锁释放,而后write获取写锁,修改数据后降级为读锁时,其他的读锁也能获取读锁,结果中锁降级与下面的读取结果同时打印。

ReentrantReadWriteLock不支持锁升级。

3 Condition

Lock提供条件Condition,对线程的等待和唤醒更加详细和灵活

内部维护一个Condition队列。当前线程调用await方法后,将会以当前线程构造为一个结点Node,并将该节点放到该队列的尾部

Condition是个接口,基本的方法就是await()和signal()方法;
Condition依赖于Lock接口,生成一个Condition的方式是lock.newCondition()

我们来看一个使用Lock + Condition多线程顺序打印A B C …的例子

应用demo

/*** @author kenewstar* @version 1.0* @date 2021/5/16*/
public class Concurrent03 {private int count;private final Lock lock = new ReentrantLock();private final Condition condition = lock.newCondition();public static void main(String[] args) {Concurrent03 c = new Concurrent03();ExecutorService service = Executors.newCachedThreadPool();service.execute(c::printA);service.execute(c::printB);service.execute(c::printC);service.shutdown();}public void printA() {lock.lock();try {while (true){if (count % 3 != 0) {condition.await();}Thread.sleep(300);System.out.print("A ");count ++;condition.signalAll();}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void printB() {lock.lock();try {while (true){if (count % 3 != 1) {condition.await();}Thread.sleep(300);System.out.print("B ");count ++;condition.signalAll();}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void printC() {lock.lock();try {while (true){if (count % 3 != 2) {condition.await();}Thread.sleep(300);System.out.print("C ");count ++;condition.signalAll();}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}
}

运行结果如下:

在这里插入图片描述

4 LockSupport

当需要阻塞或唤醒一个线程的时候,都会使用LockSupport工具类来完成相应工作,LockSupport为构建同步组件的基础工具。 LockSupport定义了一组 以park开头的方法用来阻塞当前线程,以及unpark(Thread thread)方法来唤醒一个被阻塞的线程。 Park有停车的意思,假设线程为车辆,那么park方法代表着停车,而unpark方法则是指车辆启动离开

简单应用

/*** @author kenewstar* @version 1.0* @date 2021/5/16*/
public class Concurrent13 {static class LockSupportTest extends Thread {@Overridepublic void run() {System.out.println("thread......");LockSupport.park();System.out.println("执行逻辑......");}}public static void main(String[] args) throws InterruptedException {Thread thread = new LockSupportTest();thread.start();Thread.sleep(1000);LockSupport.unpark(thread);System.out.println("main end.....");}
}

运行结果如下:

在这里插入图片描述

当调用park()方法时会阻塞当前线程,调用unpark(Thread t)时,会唤醒指定线程。


http://chatgpt.dhexx.cn/article/VvqqxGax.shtml

相关文章

lock锁

目录 1. lock 基本用法 2. lock公平锁与非公平锁 3. lock注意事项 4. synchronized 与 lock区别 1. lock 基本用法 lock.lock(); try {} finally {lock.unlock() }或者try {lock.lock(); } finally {lock.unlock() }public class ThreadLock1 {public static void main(S…

LOCKED勒索病毒解密 数据恢复

什么是LOCKED勒索病毒 LOCKED勒索病毒是由Michael Gillespie发现的。该恶意程序旨在通过加密来阻止对存储在计算机上的文件的访问。为了解密他们的文件&#xff0c;鼓励受害者购买解密工具。与大多数此类程序一样&#xff0c;[LOCKED] 重命名所有加密文件&#xff0c;在本例中…

服务器数据中了locked勒索病毒,有关locked勒索病毒的介绍与预防建议

随着网络的普及和科技技术的发展&#xff0c;网络安全问题日益突出。而其中&#xff0c;勒索病毒就是一种常见的网络安全威胁。一旦企业的服务器数据库被勒索病毒攻击&#xff0c;会导致企业内部的重要数据被加密&#xff0c;给工作和生产生活带了极大的困扰。下面就为大家介绍…

locked 勒索软件

1.Locked介绍 Locked病毒属于Void Crypt 勒索软件家族。该勒索软件会加密 PC 上的所有用户数据&#xff08;照片、文档、Excel 表格、音乐、视频等&#xff09;&#xff0c;将其特定扩展名添加到每个文件&#xff0c;并在每个包含加密文件的文件夹中创建文件。 2.我是如何在我…

MEID

MEID简介 Mobile Equipment IDentifier&#xff08;MEID&#xff09;是全球唯一的56bit移动终端标识号。标识号会被烧入终端里&#xff0c;并且不能被修改。可用来对移动式设备进行身份识别和跟踪。由于ESN号段是有限的资源&#xff0c;基本上耗尽&#xff0c;可能还有少量回收…

科谱|MEID表格如何填写,99开头,MEID怎么申请,MEID申请表填写

作为通信产品最常见的三大主流号码之一MEID最近这些年的存在感确实偏低了点&#xff0c;尽管如此还是有大量需要使用MEID号码的产品&#xff0c;及时快速准确的申请到号码还是必不可少的。 文化的差异和语言的不通会造成不大不小的麻烦&#xff0c;今天我们结合最新版的申请表…

关于安卓系统4.0/5.0/6.0获取单卡手机,双卡手机的imei1,imei2,meid(用反射来实现,史上最详细,最全面获取)--binbinyang

有的人问我要代码跟例子&#xff0c;上次在GITHUB上弄了一个&#xff0c;提供地址 给大家 https://github.com/binbinyYang/GetPhoneInfo https://github.com/binbinyYang/GetPhoneInfo -------------------------------------------------------- 最近这3天&#xff0c;一直在…

MEID 的构成

MEID 的构成如下&#xff0c;针对 Hex 格式&#xff1a; 最后一位是 CD&#xff0c;这个 CD 不是 MEID 的组成部分&#xff0c;真正的 MEID 是前 14 位。在手机与基站进行 MEID 检查时&#xff0c;手机提交的 MEID 不能包含 CD 位&#xff0c;否则就会出错。当初设计此 CD 位主…

Mina MEID/GSM Activator 1.0 三网信号激活,支持iOS12.0~14.8.1

Mina团队已经更新工具&#xff0c;现在支持MEID/GSM三网和两网解锁信号&#xff01;支持iOS14.8系统&#xff0c;两网价格和三网价格一样。 Mina MEID/GSM Activator可以激活所有MEID/GSM二网、三网恢复信号&#xff0c;并且支持打电话、短信、4G流量上网&#xff0c;支持iPhon…

高通芯片联机读取修改串码 meid ESN wifi 蓝牙 sn等参数的操作解析{二}

上次我发了几个相关联机读写参数的帖子。很多友友询问有没有其他相关软件来解读参数的教程。今天就来个续集来解析参数读写 关于安卓机型写串码 改串码 端口开启和基带qcn等一些经验 高通联机修改IMEI等参数的相关解析 高通芯片基带相关的软件 QPST QXDM DFS等等&#xff0c…

说说移动设备的各种标识码(DeviceID, IMEI, UUID, UDID, OAID, IDFA, GAID)

转战广告行业&#xff0c;收集整理一波移动设备各种标识码的含义当做基础知识储备 一、名词解释 Device ID&#xff1a;设备ID。IMEI&#xff1a;&#xff08;International Mobile Equipment Identity&#xff09;国际移动设备标识的缩写。是由15位数字组成的“电子串号”&a…

Mina MEID/GSM Activator 1.0 三网信号激活,支持12.5.3~14.7

Mina团队已经更新工具&#xff0c;现在支持MEID/GSM三网和两网解锁信号&#xff01;支持iOS14.7系统&#xff0c;两网价格和三网价格一样。 Mina MEID/GSM Activator可以激活所有MEID/GSM二网、三网恢复信号&#xff0c;并且支持打电话、短信、4G流量上网&#xff0c;支持iPhon…

Mina MEID Activator 2.120210512更新使用说明支持三网(移动、联通、电信)国行版手机解锁打电话4G苹果手机激活锁停用Hello密码锁绕ID屏幕锁密码

Mina MEID Activator 是由Minacriss开发的新工具。可以激活所有MEID三网的信号恢复&#xff0c;并且支持打电话、短信、4G流量上网。支持iPhone5sX直接所有型号&#xff0c;支持iOS12.5.2iOS14.4.2。MEID三网指&#xff1a;不小心忘记ID密码&#xff0c;而且已经刷机并且是激活…

关于IMEI、MEID、IMSI

关于IMEI、MEID、IMSI 简介 IMEI、MEID都是用于标识一台物理设备的ID信息。在Android 8.0以下系统提供的API中&#xff0c;会根据不同条件返回二者之一的信息。 IMEI&#xff1a; 国际移动设备识别码&#xff0c;是区别移动设备的标志&#xff0c;一般用于标识某一台独立的设…

2022最新手机设备标识码(IMEI、MEID、UDID、UUID、ANDROID_ID、GAID、IDFA等)教程

Android篇 1 IMEI和MEID (1) IMEI (International Mobile Equipment Identity) 是国际移动设备身份码的缩写&#xff0c;国际移动装备辨识码&#xff0c;只有Android手机才获取的到&#xff0c;是由15位数字组成的"电子串号"&#xff0c;比如像这样 35988103031435…

安卓唯一标识:IMEI,MEID,MAC地址,Android_id,UUID,OAID

目录 IMEI&#xff1a; MEID&#xff1a; MAC地址&#xff1a; Android_id&#xff1a; UUID&#xff1a; OAID&#xff1a; 安卓设备的唯一标识&#xff0c;获取的目的在于数据统计&#xff0c;广告归因分析等用途。常用作唯一标识的有IMEI&#xff0c;MEID&#xff0c;…

QA:MEID号申请、什么是MEID号、怎么申请MEID号、MEID号获取

本文671个字&#xff0c;正常大约需要阅读两分钟&#xff0c;完整阅读更精彩&#xff0c;欢迎点赞、转发或留言&#xff01; Q&#xff1a;什么是MEID号&#xff1f; A&#xff1a; MEID 移动设备识别码(Mobile Equipment Identifier)是CDMA手机的身份识别码&#xff0c;也是…

什么是MEID号如何申请MEID,A0、A1、A2以及99开头的MEID号的区别?

MEID/ESN号段ESN Manufacturer’s (MFR) Codes (ESN 厂家代码段) 主要适用于CDMA类的产品Mobile Equipment IDentifier&#xff08;MEID&#xff09;是全球唯一的56bit移动终端标识号需要向美国申请。标识号会被输入终端里&#xff0c;无法修改。可用来对移动式设备进行身份识别…

如何深入理解 StatsD 与 Graphite ?

众所周知&#xff0c;StatsD 负责收集并聚合测量值。之后&#xff0c;它会将数据传给 Graphite&#xff0c;后者以时间序列为依据存储数据&#xff0c;并绘制图表。但是&#xff0c;我们不知道&#xff0c;基于 http 访问的图表在展示时&#xff0c;是基于每秒钟的请求数&#…

graphite 监控 简介

graphite是一个监控业务数据的监控系统。&#xff0c;该系统架构如下&#xff1a; 系统分为三大组件&#xff1a; carbon&#xff1a; 负责后端数据采集,可以通过以下客户端来采集数据 客户端应用有多个方式来发布度量值&#xff1a; 使用一个纯文本协议工具比如 netcat (n…