理解java的ReetrantLock
来源:互联网 发布:电脑拍照的软件 编辑:程序博客网 时间:2024/05/07 18:35
关于java多线程并发控制,除了内置关键字synchronized外,还有lock,lock的一个实现类就是ReetrantLock,Lock可以实现更灵活的多线程并发控制。
如何使用,举个栗子
public class ReetrantLockDemo { static final Lock lock = new ReentrantLock(); static Runnable runnable1 = new Runnable() { @Override public void run() { lock.lock(); try { for (int i = 0; i < 5; i++) { System.out.println("runnable1 running " + i); } } finally { lock.unlock(); } } }; static Runnable runnable2 = new Runnable() { @Override public void run() { lock.lock(); try { for (int i = 0; i < 5; i++) { System.out.println("runnable2 running " + i); } } finally { lock.unlock(); } } }; public static void main(String[] args) { new Thread(runnable1).start(); new Thread(runnable2).start(); }}
这就是lock的最基本使用,使用lock和unlock方法对代码片进行加锁了解锁,效果和synchronized一样,两个线程串行化执行了,控制台输出如下:
runnable1 running 0
runnable1 running 1
runnable1 running 2
runnable1 running 3
runnable1 running 4
runnable2 running 0
runnable2 running 1
runnable2 running 2
runnable2 running 3
runnable2 running 4
也就是说synchronized能做的lock都能做,那么看看lock还能做什么。它还提供了trylock方法,这个方法就是说我会尝试获取锁,但获取锁如果失败,不会导致当前线程阻塞,直接跳过,把上面的栗子稍微改造一下。
public class ReetrantLockDemo { static final Lock lock = new ReentrantLock(); static Runnable runnable1 = new Runnable() { @Override public void run() { lock.lock(); try { for (int i = 0; i < 5; i++) { System.out.println("runnable1 running " + i); } } finally { lock.unlock(); } } }; static Runnable runnable2 = new Runnable() { @Override public void run() { if (lock.tryLock()) { try { for (int i = 0; i < 5; i++) { System.out.println("runnable2 running " + i); } } finally { lock.unlock(); } } else { System.out.println("Can not get the lock, skip running"); } } }; public static void main(String[] args) { new Thread(runnable1).start(); new Thread(runnable2).start(); }}
在线程2中尝试获取锁,如果获取不到,就直接跳过,控制台输出如下:
runnable1 running 0
Can not get the lock, skip running
runnable1 running 1
runnable1 running 2
runnable1 running 3
runnable1 running 4
另外trylock方法还可以设置等待时间,等待多少时间后获取不了锁就跳过。在构造ReetrantLock时可以设置一个boolean值,就是 new ReetrantLock(true/false),选择是否构造一个“公平锁”,所谓公平锁就是让所有等待线程按他们的等待顺序来得到当前锁,防止一些线程很久都不被执行,不过需要注意实现公平锁需要一些额外计算开销,慎用。
lock还有一个功能就是condition,简单的说就是条件设置。举个栗子,比如上面2个线程,需求是第一个线程循环到3的时候第二个线程开始,这时候第一个线程停止,等到第二个线程执行到3的时候在启动。那么这里就有2个条件:
1. 第二个线程需要在第一个线程执行到3的时候才能启动,用condition1表示
2. 第一个线程需要在第二个线程执行到3的时候重启。用condition2表示
public class ReetrantLockDemo { static final Lock lock = new ReentrantLock(); static boolean thread1Arrive3 = false; static boolean thread2Arrive3 = false; static final Condition condition1 = lock.newCondition(); static final Condition condition2 = lock.newCondition(); static Runnable runnable1 = new Runnable() { @Override public void run() { lock.lock(); try { for (int i = 0; i < 5; i++) { System.out.println("runnable1 running " + i); if(i==3){ thread1Arrive3=true; condition1.signal(); if(!thread2Arrive3){ condition2.await(); } } } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }; static Runnable runnable2 = new Runnable() { @Override public void run() { lock.lock(); try { if(!thread1Arrive3){ condition1.await(); } for (int i = 0; i < 5; i++) { System.out.println("runnable2 running " + i); if(i==3){ thread2Arrive3=true; condition2.signal(); } } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }; public static void main(String[] args) { new Thread(runnable1).start(); new Thread(runnable2).start(); }}
运行结果:
runnable1 running 0
runnable1 running 1
runnable1 running 2
runnable1 running 3
runnable2 running 0
runnable2 running 1
runnable2 running 2
runnable2 running 3
runnable2 running 4
runnable1 running 4
condition的await方法可以让当前线程释放锁并且在指定的condition上面进行等待,而signal方法则通知在condition上等待的线程获取锁并继续执行。condition其实维护了一个队列的数据结构,await相当于往队列中put,而signal则是从队列中取出。所以需要注意如果在执行signal时,没有线程在这个condition上去await,singal方法也不会阻塞。所以需要注意使用condition的时候一定是在满足条件的时候才去进行await和signal(示例代码中使用2个boolean变量作为判定条件),如果signal先执行,await后执行就直接死锁了。
- 理解java的ReetrantLock
- ReadWriteLock和ReetrantLock的区别
- 用ReetrantLock来分析java并发中不可错过的类AbstractQueuedSynchronizer
- Java中ReetrantLock与Synchronized对比
- 关于synchronized以及ReetrantLock、ReentrantReadWriteLock的选择
- ReetrantLock Synchronized Atomic的性能对比
- 深入剖析基于并发AQS的(独占锁)重入锁(ReetrantLock)及其Condition实现原理
- 深入剖析基于并发AQS的(独占锁)重入锁(ReetrantLock)及其Condition实现原理
- java多线程的理解
- Java多态性的理解
- 理解java的异常
- 理解java的File
- 理解java的clone
- java 多态性的理解
- java引用的理解
- JAVA时间的理解
- java-servlet的理解
- java虚拟机的理解
- ajax 请求xml格式数据的省市联动
- java中length,length(),和size()的区别
- PHP清空缓存 clearstatcache()
- NOIP2015复赛DAY1
- javascript 内置对象 - 数组对象&方法 concat join reverse
- 理解java的ReetrantLock
- caffe在Windows下配置 vs2013+cuda7.5+python2.7/python3.5/matlab
- 去除vue插值表达式{{}}
- 第20章:错误处理(119)
- javascript 内置对象 - 数组的排序
- linux利用转crt和key转换keystore文件
- 动态规划
- Jmeter+Badbody 实现带登录的压力测试
- USB学习3