【并发】Lock与ReentrantLock

2024-09-03 14:58
文章标签 并发 lock reentrantlock

本文主要是介绍【并发】Lock与ReentrantLock,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 Lock基本使用

Lock能实现代码同步,它比synchronized更具灵活性,什么时候锁住,什么时候释放锁等都是看得见的,使用时必须使用try{}finally{},意思是万一发生异常或者错误都可以释放锁。

try{
}finally{//释放锁
}
  • 使用示例
public class SaleTicket implements Runnable {private int ticket = 10 * 100000;private Lock mLock = new ReentrantLock();@Overridepublic void run() {try {while (ticket > 0) {mLock.lock();if(ticket>0){if (ticket % 100000 == 0) {System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + (ticket / 100000) + "张票");}ticket--;}}} finally {mLock.unlock();}}
}
        Runnable saleTicket = new SaleTicket();Thread thread1 = new Thread(saleTicket);Thread thread2 = new Thread(saleTicket);Thread thread3 = new Thread(saleTicket);Thread thread4 = new Thread(saleTicket);thread1.start();thread2.start();thread3.start();thread4.start();

结果:
image.png

2 ReentrantLock

ReentrantLock有两种锁机制:忽略中断锁和响应中断锁。如:如果A、B两个线程去竞争锁,A获得锁,B等待,但A线程要做的事情太多,一直不返回锁,B线程就想先中断自己不再等待这个锁,转而去处理其他事情。这时候ReentrantLock提供了2种机制,第一种,B线程中断自己(或者别的线程中断它),但是ReentrantLock不去响应,继续让B线程等待,这就是忽略中断锁(lock());第二种,B线程中断自己(或者别的线程中断它),ReentrantLock处理了这个中断,并且不再等待这个锁的到来,完全放弃,这就是响应中断锁(lockInterruptibly())。

  • 响应中断锁示例:
public class BufferInterruptibly {private ReentrantLock mLock = new ReentrantLock();public void write(){mLock.lock();try {long startTime = System.currentTimeMillis();System.out.println("开始往这个buff写入数据…");for (; ; ) {if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE) {break;}}System.out.println("终于写完了");}finally {mLock.unlock();}}public void read() throws InterruptedException{mLock.lockInterruptibly();try{System.out.println("从这个buff读数据");}finally {mLock.unlock();}}
}
final BufferInterruptibly buff = new BufferInterruptibly();Thread write = new Thread(new Runnable() {@Overridepublic void run() {buff.write();}});final Thread read = new Thread(new Runnable() {@Overridepublic void run() {try{Thread.sleep(500);buff.read();}catch (Exception e){System.out.println("我不读了");}System.out.println("读结束");}});write.start();read.start();new Thread(new Runnable() {@Overridepublic void run() {long start = System.currentTimeMillis();for (;;){if (System.currentTimeMillis()-start>500){System.out.println("不等了,尝试中断");read.interrupt();break;}}}}).start();

结果:
image.png

ReentrantLock叫做重入锁,意思是外层方法获取到锁后,内层方法会自动获取到锁。synchronized也是可重入锁。我们先看一下synchronized锁的可重入性

class SychronizedReentrant implements Runnable{private Object object = new Object();/*** 方法一调用方法二*/public void method1(){synchronized (object){System.out.println(Thread.currentThread().getName()+ " method1 ");method2();}}/**方法二,打印获取obj锁如果是同一线程,锁不可以重入,method2需要等待method1释放锁*/public void method2(){synchronized (object){System.out.println(Thread.currentThread().getName()+ " method2 ");}}@Overridepublic void run() {method1();}
}

结果

Thread-0 method1
Thread-0 method2

method1有一个同步块,同步块中调用了method2,而method2中也有个同步块,一般来说,synchronized块里面的内容执行完才会释放锁,其它synchronized块才能竞争到锁,而向上述调用步骤,明显是外部方法的synchronized还没有释放锁,内部方法的synchronized就可以得到锁,这就是重入锁。

例子(摘抄网上):

package tags;import java.util.Calendar;public class TestLock {private ReentrantLock lock = null;public int data = 100;     // 用于线程同步访问的共享数据public TestLock() {lock = new ReentrantLock(); // 创建一个自由竞争的可重入锁}public ReentrantLock getLock() {return lock;}public void testReentry() {lock.lock();Calendar now = Calendar.getInstance();System.out.println(now.getTime() + " " + Thread.currentThread()    + " get lock.");}public static void main(String[] args) {TestLock tester = new TestLock();//1、测试可重入tester.testReentry();tester.testReentry(); // 能执行到这里而不阻塞,表示锁可重入tester.testReentry(); // 再次重入// 释放重入测试的锁,要按重入的数量解锁,否则其他线程无法获取该锁。tester.getLock().unlock();tester.getLock().unlock();tester.getLock().unlock();//2、测试互斥// 启动3个线程测试在锁保护下的共享数据data的访问new Thread(new workerThread(tester)).start();new Thread(new workerThread(tester)).start();new Thread(new workerThread(tester)).start();}// 线程调用的方法public void testRun() throws Exception {lock.lock();Calendar now = Calendar.getInstance();try {// 获取锁后显示 当前时间 当前调用线程 共享数据的值(并使共享数据 + 1)System.out.println(now.getTime() + " " + Thread.currentThread()+ " accesses the data " + data++);Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}
}// 工作线程,调用TestServer.testRun
class workerThread implements Runnable {private TestLock tester = null;public workerThread(TestLock testLock) {this.tester = testLock;}public void run() {try {tester.testRun();} catch (Exception e) {e.printStackTrace();}}
}

这篇关于【并发】Lock与ReentrantLock的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1133283

相关文章

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

Spring Security 前后端分离场景下的会话并发管理

《SpringSecurity前后端分离场景下的会话并发管理》本文介绍了在前后端分离架构下实现SpringSecurity会话并发管理的问题,传统Web开发中只需简单配置sessionManage... 目录背景分析传统 web 开发中的 sessionManagement 入口ConcurrentSess

MySQL中处理数据的并发一致性的实现示例

《MySQL中处理数据的并发一致性的实现示例》在MySQL中处理数据的并发一致性是确保多个用户或应用程序同时访问和修改数据库时,不会导致数据冲突、数据丢失或数据不一致,MySQL通过事务和锁机制来管理... 目录一、事务(Transactions)1. 事务控制语句二、锁(Locks)1. 锁类型2. 锁粒

深入解析Java NIO在高并发场景下的性能优化实践指南

《深入解析JavaNIO在高并发场景下的性能优化实践指南》随着互联网业务不断演进,对高并发、低延时网络服务的需求日益增长,本文将深入解析JavaNIO在高并发场景下的性能优化方法,希望对大家有所帮助... 目录简介一、技术背景与应用场景二、核心原理深入分析2.1 Selector多路复用2.2 Buffer

C#中lock关键字的使用小结

《C#中lock关键字的使用小结》在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时,其他线程无法访问同一实例的该代码块,下面就来介绍一下lock关键字的使用... 目录使用方式工作原理注意事项示例代码为什么不能lock值类型在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使

解决mysql插入数据锁等待超时报错:Lock wait timeout exceeded;try restarting transaction

《解决mysql插入数据锁等待超时报错:Lockwaittimeoutexceeded;tryrestartingtransaction》:本文主要介绍解决mysql插入数据锁等待超时报... 目录报错信息解决办法1、数据库中执行如下sql2、再到 INNODB_TRX 事务表中查看总结报错信息Lock

python多线程并发测试过程

《python多线程并发测试过程》:本文主要介绍python多线程并发测试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、并发与并行?二、同步与异步的概念?三、线程与进程的区别?需求1:多线程执行不同任务需求2:多线程执行相同任务总结一、并发与并行?1、