多线程编程-ReentrantLock(八) 阳光穿透心脏的1/2处 2022-06-01 03:48 201阅读 0赞 1,在java多线程中,可以使用synchronized关键字实现线程间同步互斥,也可以使用ReentrantLock达到同样的效果。ReentrantLock拥有一些扩展功能,如:等待可中断,可实现公平锁,锁可以绑定多个条件,尝试锁定等。 测试代码: public class MyService { private Lock lock = new ReentrantLock(); public void methodA(){ try { lock.lock(); System.out.println("methodA begin threadName="+Thread.currentThread().getName() +",time="+System.currentTimeMillis()); Thread.sleep(2000); System.out.println("methodA end threadName="+Thread.currentThread().getName() +",time="+System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); }finally{ lock.unlock(); } } public void methodB(){ try { lock.lock(); System.out.println("methodB begin threadName="+Thread.currentThread().getName() +",time="+System.currentTimeMillis()); Thread.sleep(2000); System.out.println("methodB end threadName="+Thread.currentThread().getName() +",time="+System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); }finally{ lock.unlock(); } } } 避免忘记调用lock.unlock,通常将其放在try-finally\{\}中。 public class ThreadA extends Thread { private MyService service; public ThreadA(MyService service){ this.service = service; } @Override public void run() { service.methodA(); } } public class ThreadB extends Thread { private MyService service; public ThreadB(MyService service){ this.service = service; } @Override public void run() { service.methodB(); } } public class RunTest { public static void main(String[] args) { MyService service = new MyService(); ThreadA ta = new ThreadA(service); ta.setName("A"); ta.start(); ThreadB tb = new ThreadB(service); tb.setName("B"); tb.start(); } } 运行结果: methodA begin threadName=A,time=1516327240816 methodA end threadName=A,time=1516327242816 methodB begin threadName=B,time=1516327242816 methodB end threadName=B,time=1516327244816 调用lock.lock()的线程持有了“对象监视器”,其他线程只有等待锁释放时再次争抢,效果和使用synchronized关键字一样,线程之间是顺序执行的。 2,类ReentrantLock搭配Condition类。 Synchronized配合wait(),notify(),notifyAll()可以实现等待/通知机制。类ReentrantLock借助Condition类,也可以实现同样的功能,而且可以实现多路通知功能,就是在一个Lock对象中创建多个Condition实例(对象监视器),线程对象可以注册在指定的Condition中,从而可以有选择地进行线程通知,在调度线程上更加灵活。 在使用notify()/notifyAll()进行通知时,被通知的线程是由JVM随机选择的。使用ReentrantLock结合Condition可以实现“选择性通知”。 测试代码: public class MyService { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void awaitMethod(){ try { lock.lock(); System.out.println("before condition.await(),time="+System.currentTimeMillis()); condition.await(); System.out.println("after condition.await()"); } catch (InterruptedException e) { e.printStackTrace(); }finally{ lock.unlock(); System.out.println("awaitMethod(),release lock.)"); } } public void signalMethod(){ try{ lock.lock(); System.out.println("condition.signal(),time="+System.currentTimeMillis()); condition.signal(); }finally{ lock.unlock(); System.out.println("signalMethod(),release lock.)"); } } } Condition的await(),signal()方法,调用前,需要调用lock.lock()方法获取同步监视器,否则会报异常java.lang.IllegalMonitorStateException。 public class ThreadA extends Thread { private MyService service; public ThreadA(MyService service){ this.service = service; } @Override public void run() { service.awaitMethod(); } } public class RunTest { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); ThreadA ta = new ThreadA(service); ta.setName("A"); ta.start(); Thread.sleep(2000); service.signalMethod(); } } 运行结果: before condition.await(),time=1516329903013 condition.signal(),time=1516329905013 after condition.await() awaitMethod(),release lock.) signalMethod(),release lock.) 如此就实现了等待/通知模式,Condition类中的awati(),signal(),signalAll()方法相当于Object类中的wait(),nofity(),notifyAll()。 3, 如果想单独唤醒部分线程,就要使用多个 Condition 对象, Condition 对象可以唤醒部分指定线程,先对线程进行分组,然后在唤醒指定组中的线程。 测试代码: public class MyService { private Lock lock = new ReentrantLock(); private Condition conditionA = lock.newCondition(); private Condition conditionB = lock.newCondition(); public void awaitMethodA(){ try { lock.lock(); System.out.println("before condition.await()-A,time="+System.currentTimeMillis() +"ThreadName="+Thread.currentThread().getName()); conditionA.await(); System.out.println("after condition.await()-A"+"ThreadName="+Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); }finally{ lock.unlock(); System.out.println("awaitMethod()-A,release lock."); } } public void signalMethodA(){ try{ lock.lock(); System.out.println("condition.signal()-A,time="+System.currentTimeMillis()); conditionA.signalAll(); }finally{ lock.unlock(); System.out.println("signalMethod()-A,release lock."); } } public void awaitMethodB(){ try { lock.lock(); System.out.println("before condition.await()-B,time="+System.currentTimeMillis() +"ThreadName="+Thread.currentThread().getName()); conditionB.await(); System.out.println("after condition.await()-B"+"ThreadName="+Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); }finally{ lock.unlock(); System.out.println("awaitMethod()-B,release lock."); } } public void signalMethodB(){ try{ lock.lock(); System.out.println("condition.signal()-B,time="+System.currentTimeMillis()); conditionB.signalAll(); }finally{ lock.unlock(); System.out.println("signalMethod()-B,release lock."); } } } public class ThreadA extends Thread { private MyService service; public ThreadA(MyService service){ this.service = service; } @Override public void run() { service.awaitMethodA(); } } public class ThreadB extends Thread { private MyService service; public ThreadB(MyService service){ this.service = service; } @Override public void run() { service.awaitMethodB(); } } public class RunTest { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); ThreadA ta = new ThreadA(service); ta.setName("A"); ta.start(); ThreadB tb = new ThreadB(service); tb.setName("B"); tb.start(); Thread.sleep(2000); service.signalMethodA(); } } 运行结果: before condition.await()-A,time=1516331056387ThreadName=A before condition.await()-B,time=1516331056387ThreadName=B condition.signal()-A,time=1516331058387 signalMethod()-A,release lock. after condition.await()-AThreadName=A awaitMethod()-A,release lock. 只唤醒了等待在conditionA上的线程。 4, ReentrantLock分“公平锁”、“非公平锁”,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的。而非公平锁时一种获取锁的抢占机制,是随机获取锁的。 在创建对象时,可以通过构造函数的参数选择使用公平锁还是非公平锁: **public** ReentrantLock(**boolean**fair)\{\}。 ReentrantLock类的方法: 1) 方法int getHoldCount(),查询当前线程保持在这个锁定上的个数,也就是调用lock()方法的次数。 2) 方法int getQueueLength(),返回正在等待获取此锁定的线程估计数,如果有5个线程,一个线程先执行了await()方法,然后调用getQueueLength()返回值是4,说明有4个线程同时在等待此lock的释放。 3) 方法intgetWaitQueueLength(Condition condition),返回等待与此锁定相关的给定条件condition的线程估计数,比如有5个线程,每个线程都执行了同一个condition对象的await()方法,调用这个方法时返回值是5。 1) 方法boolean hasQueuedThread(Threadthread),查询指定的线程是否正在等待获取此锁定。 2) 方法booleanhasQueuedThreads(),查询是否有线程正在等待获取此锁定。 3) 方法boolean hasWaiters(Conditioncondition),查询是否有线程正在等待与此锁定有关的condition条件。 4) 方法boolean isFair(),判断是否公平锁。 5) 方法booleanisHeldByCurrentThread(),查询当前线程是否保持此锁定。 6) 方法boolean isLocked(),查询此锁定是否由任意线程保持。 7) 方法void lockInterruptibly(),如果当前线程未被中断,则获取锁定,如果已经被中断则抛出异常:java.lang.InterruptedException 8) 方法boolean tryLock(),在调用时,锁未被另一个线程保持的情况下,才获取该锁定。 9) 方法boolean tryLock(longtime, TimeUnit unit),如果锁定在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。 Condition的方法 1) 方法voidawaitUninterruptibly(),当一个线程在condition上await时,被中断不会抛出异常。
相关 多线程编程:Java并发控制工具Lock/ReentrantLock 在Java中,多线程编程中的锁(Lock)和可重入锁(ReentrantLock)是用于同步、互斥的工具。 1. Lock:是最基础的锁,一旦获取就无法释放,适用于需要强制互 我就是我/ 2024年09月12日 09:09/ 0 赞/ 55 阅读
相关 Java多线程(七):ReentrantLock 加锁和解锁 我们来看下ReentrantLock的基本用法 ThreadDomain35类 public class ThreadDomain35 { pr 心已赠人/ 2023年08月17日 15:16/ 0 赞/ 125 阅读
相关 多线程--ReentrantLock--原理 原文网址:[多线程--ReentrantLock--原理\_IT利刃出鞘的博客-CSDN博客][--ReentrantLock--_IT_-CSDN] 其他网址、 [R 电玩女神/ 2023年07月20日 05:44/ 0 赞/ 115 阅读
相关 【多线程并发编程】八 线程的礼让和守护线程 > 程序猿学社的GitHub,欢迎Star > [https://github.com/ITfqyd/cxyxs][https_github.com_ITfqyd_cxyx 港控/mmm°/ 2023年07月08日 12:25/ 0 赞/ 11 阅读
相关 多线程编程(八)volatile关键字 volatile关键字 目录 volatile关键字 1. 作用 2. 什么时候用 1. 作用 > 一个共享变量(类的成员变 蔚落/ 2022年12月21日 06:17/ 0 赞/ 188 阅读
相关 多线程-ReentrantLock package cn.stu; import java.util.Calendar; import java.util.concurrent. 冷不防/ 2022年07月15日 00:01/ 0 赞/ 161 阅读
相关 多线程编程-ReentrantReadWriteLock(八) ReentrantReadWriteLock类 1,ReentrantLock类具有完全互斥排他的效果,即同一时刻只有一个线程在执行ReentrantLock().lock( 水深无声/ 2022年06月01日 04:11/ 0 赞/ 195 阅读
相关 多线程编程-ReentrantLock(八) 1,在java多线程中,可以使用synchronized关键字实现线程间同步互斥,也可以使用ReentrantLock达到同样的效果。ReentrantLock拥有一些扩展功能 阳光穿透心脏的1/2处/ 2022年06月01日 03:48/ 0 赞/ 202 阅读
相关 Java 多线程(四)——线程同步(synchronized、ReentrantLock) 同步,是指协同步调,按预定的先后次序进行运行。而不是从字面上理解的“一起工作”。 1 一个线程安全问题 银行取钱问题:使用两个线程来模拟两个人对同一账户取钱操作。 心已赠人/ 2022年01月11日 08:47/ 0 赞/ 385 阅读
还没有评论,来说两句吧...