ReentranLock
Reentrantlock
JDK1.5新增的ReentrantLock类,重入锁。
ReentrantLock是独占锁且可重入的
ReentrantLock和synchronized
相同点:
-
ReentrantLock和synchronized都是独占锁,只允许线程互斥的访问临界区
-
ReentrantLock和synchronized都是可重入的
不同点:
-
synchronized加锁解锁的过程是隐式的,用户不用手动操作,优点是操作简单,但显得不够灵活;ReentrantLock需要手动加锁和解锁,且解锁的操作尽量要放在finally代码块中,保证线程正确释放锁。ReentrantLock操作较为复杂,但是因为可以手动控制加锁和解锁过程,在复杂的并发场景中能派上用场。
-
ReentrantLock和synchronized都是可重入的。
-
synchronized因为可重入,因此可以放在被递归执行的方法上,且不用担心线程最后能否正确释放锁;
-
而ReentrantLock在重入时要确保重复获取锁的次数必须和重复释放锁的次数一样,否则可能导致其他线程无法获得该锁。
-
-
ReentrantLock可以实现公平锁
-
公平锁是指当锁可用时,在锁上等待时间最长的线程将获得锁的使用权。而非公平锁则随机分配这种使用权。
-
和synchronized一样,默认的ReentrantLock实现是非公平锁,因为相比公平锁,非公平锁性能更好。当然公平锁能防止饥饿,某些情况下也很有用。
-
在创建ReentrantLock的时候通过传进参数
true
创建公平锁,如果传入的是false
或没传参数则创建的是非公平锁ReentrantLock lock = new ReentrantLock(true);
-
-
ReentrantLock可响应中断
-
当使用synchronized实现锁时,阻塞在锁上的线程除非获得锁否则将一直等待下去,也就是说这种无限等待获取锁的行为无法被中断
-
而ReentrantLock提供了一个可以响应中断的获取锁的方法
lockInterruptibly()
。该方法可以用来解决死锁问题。
-
-
获取锁时限时等待
ReentrantLock还提供了获取锁限时等待的方法
tryLock()
,可以选择传入时间参数,表示等待指定的时间,无参则表示立即返回锁申请的结果:true表示获取锁成功,false表示获取锁失败。可以使用该方法配合失败重试机制来更好的解决死锁问题。
ReentrantLock实现同步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | package ReentrantLockTest; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //ReentrantLock实现同步 public class ReenTrantTest1 { public static void main(String[] args) { Service service = new Service(); MyThread t1 = new MyThread(service); MyThread t2 = new MyThread(service); MyThread t3 = new MyThread(service); MyThread t4 = new MyThread(service); MyThread t5 = new MyThread(service); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } } class Service { private Lock lock= new ReentrantLock(); public void testMethod(){ lock.lock(); //获取锁 for ( int i= 0 ;i< 5 ;i++){ System.out.println( "ThreadName=" +Thread.currentThread().getName()+ " " +(i+ 1 )); } lock.unlock(); //释放锁 } } class MyThread extends Thread{ private Service service; public MyThread(Service service){ this .service=service; } @Override public void run() { service.testMethod(); } } /* ThreadName=Thread-0 1 ThreadName=Thread-0 2 ThreadName=Thread-0 3 ThreadName=Thread-0 4 ThreadName=Thread-0 5 ThreadName=Thread-1 1 ThreadName=Thread-1 2 ThreadName=Thread-1 3 ThreadName=Thread-1 4 ThreadName=Thread-1 5 ThreadName=Thread-2 1 ThreadName=Thread-2 2 ThreadName=Thread-2 3 ThreadName=Thread-2 4 ThreadName=Thread-2 5 ThreadName=Thread-3 1 ThreadName=Thread-3 2 ThreadName=Thread-3 3 ThreadName=Thread-3 4 ThreadName=Thread-3 5 ThreadName=Thread-4 1 ThreadName=Thread-4 2 ThreadName=Thread-4 3 ThreadName=Thread-4 4 ThreadName=Thread-4 5 */ |
ReentrantLock结合Condition的await()、signal()实现有选择的wait()/notify()功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | package ReentrantLockTest; import java.util.concurrent.locks.*; //ReentrantLock结合Condition的await()、signal()实现有选择的wait()/notify()功能 public class ReentrantLock_Condition { public static void main(String[] args) { Service1 service1 = new Service1(); AThread t1 = new AThread(service1); BThread t2 = new BThread(service1); t1.start(); try { Thread.sleep( 500 ); } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); } } class Service1{ private Lock lcok= new ReentrantLock(); private Condition condition=lcok.newCondition(); public void await(){ try { lcok.lock(); System.out.println( "await时间为:" +System.currentTimeMillis()); condition.await(); System.out.println( "...await之后的语句会在signal执行之后继续执行" ); } catch (InterruptedException e) { e.printStackTrace(); } finally { lcok.unlock(); } } public void signal(){ try { lcok.lock(); System.out.println( "signal的时间为:" +System.currentTimeMillis()); condition.signal(); } finally { lcok.unlock(); } } } class AThread extends Thread{ private Service1 service1; public AThread(Service1 service1){ this .service1=service1; } @Override public void run() { service1.await(); } } class BThread extends Thread{ private Service1 service1; public BThread(Service1 service1){ this .service1=service1; } @Override public void run() { service1.signal(); } } |
Unsafe
执行await()方法实现线程的暂停运行的原理是:并发包源代码内部执行了 Unsafe 类的public native void park(boolean isAbsoult, long time)
;
public native void park(boolean isAbsoult, long time);
http://cnblogs.com/throwable/p/9139947.html
http://blog.csdn.net/sinat_27593959/article/details/103637818
可以通过反射的方式来创建一个实例来:
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
通过这个Unsafe实例,可以进行内存管理、线程挂起和恢复、多线程同步、内存屏障等
使用多个Condition可以实现堆指定线程的唤醒
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | package ReentrantLockTest; import java.util.concurrent.locks.*; //ReentrantLock结合Condition的await()、signal()实现有选择的wait()/notify()功能 public class ReentrantLock_Condition { public static void main(String[] args) { Service1 service1 = new Service1(); AThread t1 = new AThread(service1); BThread t2 = new BThread(service1); t1.start(); t2.start(); try { Thread.sleep( 500 ); } catch (InterruptedException e) { e.printStackTrace(); } service1.signalA(); } } class Service1{ private Lock lcok= new ReentrantLock(); private Condition conditionA=lcok.newCondition(); private Condition conditionB=lcok.newCondition(); public void awaitA(){ try { lcok.lock(); System.out.println(Thread.currentThread().getName()+ "await时间为:" +System.currentTimeMillis()); conditionA.await(); System.out.println(Thread.currentThread().getName()+ "...await之后的语句会在signal执行之后继续执行" ); } catch (InterruptedException e) { e.printStackTrace(); } finally { lcok.unlock(); } } public void awaitB(){ try { lcok.lock(); System.out.println(Thread.currentThread().getName()+ "await时间为:" +System.currentTimeMillis()); conditionB.await(); System.out.println(Thread.currentThread().getName()+ "...await之后的语句会在signal执行之后继续执行" ); } catch (InterruptedException e) { e.printStackTrace(); } finally { lcok.unlock(); } } public void signalA(){ try { lcok.lock(); System.out.println( "signal的时间为:" +System.currentTimeMillis()); conditionA.signalAll(); } finally { lcok.unlock(); } } public void signalB(){ try { lcok.lock(); System.out.println( "signal的时间为:" +System.currentTimeMillis()); conditionB.signalAll(); } finally { lcok.unlock(); } } } class AThread extends Thread{ private Service1 service1; public AThread(Service1 service1){ this .service1=service1; } @Override public void run() { service1.awaitA(); } } class BThread extends Thread{ private Service1 service1; public BThread(Service1 service1){ this .service1=service1; } @Override public void run() { service1.awaitB(); } } /* Thread-0await时间为:1609579565800 Thread-1await时间为:1609579565801 signal的时间为:1609579566297 Thread-0...await之后的语句会在signal执行之后继续执行//只唤醒了A线程 */ |
实现生产者/消费者多对多交替输出
可能会出现死锁
package ReentrantLockTest; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //使用ReentrantLock和Condition实现生产者/消费者多对多交替输出 public class AlternateTest { public static void main(String[] args) { Service2 service2 = new Service2(); setThread[] setThread = new setThread[10]; getThread[] getThread = new getThread[10]; for(int i=0;i<10;i++){ setThread[i]=new setThread(service2); getThread[i]=new getThread(service2); setThread[i].start(); getThread[i].start(); } } } class Service2 { private Lock lock=new ReentrantLock(); private Condition condition=lock.newCondition(); private boolean hasValue=false; public void set(){ try { lock.lock(); if(hasValue==true){ condition.await(); } System.out.println("生产:★"); hasValue=true; condition.signalAll(); //condition.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void get(){ try { lock.lock(); if(hasValue==false){ condition.await(); } System.out.println("消耗:⭐"); hasValue=false; condition.signalAll();//其实也会出现死锁?? //condition.signal();//出现死锁 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } class getThread extends Thread{ private Service2 service2; public getThread(Service2 service2){ this.service2=service2; } @Override public void run() { service2.get(); } } class setThread extends Thread{ private Service2 service2; public setThread(Service2 service2){ this.service2=service2; } @Override public void run() { service2.set(); } }
实现线程的交替打印
package Alternate; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //实现线程的交替执行 public class AlternateExe { public static void main(String[] args) { Service service = new Service(); for(int i=0;i<5;i++){ MyThread3 t3 = new MyThread3(service); MyThread2 t2 = new MyThread2(service); MyThread1 t1 = new MyThread1(service); t1.start(); t2.start(); t3.start(); } } } class Service{ private Lock lcok= new ReentrantLock(); private Condition condition=lcok.newCondition(); volatile private int nextWhoPrint=1;//volatile可以省略 public void test1(){ try { lcok.lock(); while(nextWhoPrint!=1) condition.await(); System.out.println("AAA"); nextWhoPrint=2; condition.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lcok.unlock(); } } public void test2(){ try { lcok.lock(); while(nextWhoPrint!=2) condition.await(); System.out.println("BBB"); nextWhoPrint=3; condition.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lcok.unlock(); } } public void test3(){ try { lcok.lock(); while(nextWhoPrint!=3) condition.await(); System.out.println("CCC"); nextWhoPrint=1; condition.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lcok.unlock(); } } } class MyThread1 extends Thread{ private Service service; public MyThread1(Service service){ this.service=service; } @Override public void run() { service.test1(); } } class MyThread2 extends Thread{ private Service service; public MyThread2(Service service){ this.service=service; } @Override public void run() { service.test2(); } } class MyThread3 extends Thread{ private Service service; public MyThread3(Service service){ this.service=service; } @Override public void run() { service.test3(); } } /* AAA BBB CCC AAA BBB CCC AAA BBB CCC AAA BBB CCC AAA BBB CCC */
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· “你见过凌晨四点的洛杉矶吗?”--《我们为什么要睡觉》
· 编程神器Trae:当我用上后,才知道自己的创造力被低估了多少
· C# 从零开始使用Layui.Wpf库开发WPF客户端
· C#/.NET/.NET Core技术前沿周刊 | 第 31 期(2025年3.17-3.23)
· 接口重试的7种常用方案!