重入锁ReentrantLock
来源:互联网 发布:知乎关于网络文章 编辑:程序博客网 时间:2024/05/01 07:00
线程的同步控制,最基础的就是synchronized关键字。但是在使用的过程中有一些限制,并没有那么的灵活。
可重入
上面代码一共起了两个线程,故意造成了死锁的状态。此时在主线程中调用了中断方法,此时t2线程对出等待,释放锁资源,从而可以让t1继续执行下去。
超时限制
当多线程对同一监视器对象加锁时,如果超过一定时间还没获得锁,则立即返回false。这里使用到的是tryLock()。
另外tryLock()不带参的方法,表示对当前对象加锁,如果获取不到则立即返回false。通过这个特性,可以在程序中用无限循环,使其不断的去尝试加锁。
在大部分的应用场景下,锁的申请获取都是不公平的。但是我们通过ReentrantLock可以构造出公平的锁对象。
综上所述
一般来说,根据JVM的调度,系统更倾向于把锁给当前已经获得锁的线程。从而减少线程频繁切换带来的系统消耗。
对于ReentrantLock主要有以下几个方法:
可重入
所以下面介绍一下ReentrantLock的使用和相关特性,一个简单的demo如下:
public class ReenterLock implements Runnable {public static ReentrantLock lock = new ReentrantLock();public static int i = 0;@Overridepublic void run() {for (int j = 0; j < 10000000; j++) {lock.lock();try {i++;} finally {lock.unlock();}}}public static void main(String[] args) throws InterruptedException {ReenterLock r1 = new ReenterLock();Thread t1 = new Thread(r1);Thread t2 = new Thread(r1);t1.start();t2.start();t1.join();t2.join();System.out.println(i);}}
上面的demo创建了两个线程 t1、t2,并且同时使用了lock作为锁,完成了i++的操作。这里面需要注意的是,lock.lock()调用了几次,响应的lock.unlock()就应该调用几次。并且无论执行体如何,最终都要调用lock.unlock()。
响应中断
在两个线程同时抢占同一个锁资源的时候,很有可能产生死锁的现象。ReentrantLock可以支持中断响应,从而规避死锁的产生。
public class IntLock implements Runnable {public static ReentrantLock lock1 = new ReentrantLock();public static ReentrantLock lock2 = new ReentrantLock();int lock;/** * 控制加锁顺序,方便构造死锁 * * @param lock */public IntLock(int lock) {this.lock = lock;}@Overridepublic void run() {try {if (lock == 1) {lock1.lockInterruptibly();try {Thread.sleep(500);} catch (Exception e) {}lock2.lockInterruptibly();} else {lock2.lockInterruptibly();try {Thread.sleep(500);} catch (Exception e) {}lock1.lockInterruptibly();}} catch (Exception e) {e.printStackTrace();} finally {if (lock1.isHeldByCurrentThread()) {lock1.unlock();}if (lock2.isHeldByCurrentThread()) {lock2.unlock();}System.out.println(Thread.currentThread().getId() + ":线程退出");}}public static void main(String[] args) throws InterruptedException {IntLock r1 = new IntLock(1);IntLock r2 = new IntLock(2);Thread t1 = new Thread(r1);Thread t2 = new Thread(r2);t1.start();t2.start();Thread.sleep(1000);// 中断t2线程t2.interrupt();}}从上面代码可以看出来,此时使用的是lock.lockInterruptibly(),而不是lock.lock()。当使用lock.lockInterruptibly()加锁等待的时候,可以响应中断,从而使线程对出死锁状态。
上面代码一共起了两个线程,故意造成了死锁的状态。此时在主线程中调用了中断方法,此时t2线程对出等待,释放锁资源,从而可以让t1继续执行下去。
超时限制
当多线程对同一监视器对象加锁时,如果超过一定时间还没获得锁,则立即返回false。这里使用到的是tryLock()。
public class TimeLock implements Runnable {public static ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {try {if (lock.tryLock(5, TimeUnit.SECONDS)) {Thread.sleep(6000);} else {System.out.println("I got lock failed.");}} catch (Exception e) {e.printStackTrace();} finally {if (lock.isHeldByCurrentThread()) {lock.unlock();}}}public static void main(String[] args) {TimeLock time1 = new TimeLock();Thread t1 = new Thread(time1);Thread t2 = new Thread(time1);t1.start();t2.start();}}上述代码启动了2个线程,在5S内必定一个线程获取锁对象失败。
另外tryLock()不带参的方法,表示对当前对象加锁,如果获取不到则立即返回false。通过这个特性,可以在程序中用无限循环,使其不断的去尝试加锁。
public class TryLock implements Runnable {public static ReentrantLock lock1 = new ReentrantLock();public static ReentrantLock lock2 = new ReentrantLock();int lock;public TryLock(int lock) {this.lock = lock;}@Overridepublic void run() {if (lock == 1) {while (true) {if (lock1.tryLock()) {try {try {Thread.sleep(500);} catch (Exception e) {}if (lock2.tryLock()) {try {System.out.println(Thread.currentThread().getId() + ": my job done");return;} finally {lock2.unlock();}}} finally {lock1.unlock();}}}} else {while (true) {if (lock2.tryLock()) {try {try {Thread.sleep(500);} catch (Exception e) {}if (lock1.tryLock()) {try {System.out.println(Thread.currentThread().getId() + ": my job done");return;} finally {lock1.unlock();}}} finally {lock2.unlock();}}}}}public static void main(String[] args) {TryLock r1 = new TryLock(1);TryLock r2 = new TryLock(2);Thread t1 = new Thread(r1);Thread t2 = new Thread(r2);t1.start();t2.start();}}公平锁
在大部分的应用场景下,锁的申请获取都是不公平的。但是我们通过ReentrantLock可以构造出公平的锁对象。
public ReentrantLock(boolean fair)使用上述方法可以构造出公平锁出来,我们通常默认的fair都是false。公平锁本身会维护一个有序队列,开销相对较高。
public class FairLock implements Runnable {public static ReentrantLock fairLock = new ReentrantLock(true);@Overridepublic void run() {while (true) {try {fairLock.lock();System.out.println(Thread.currentThread().getName() + " 获得锁");} finally {fairLock.unlock();}}}public static void main(String[] args) {FairLock r1 = new FairLock();Thread t1 = new Thread(r1, "thread t1");Thread t2 = new Thread(r1, "Thread t2");t1.start();t2.start();}}通过运行上述程序可以看出,锁的获取都是有序的,公平的。
综上所述
一般来说,根据JVM的调度,系统更倾向于把锁给当前已经获得锁的线程。从而减少线程频繁切换带来的系统消耗。
对于ReentrantLock主要有以下几个方法:
- lock():获取锁,如果已被占用,则等待;
- lockInterruptibly():获得锁,但是响应中断;
- tryLock():获得锁,如可以立即获得,则返回true,如不可以,则立即返回false;
- tryLock(long time, TimeUnit unit):超时未获得锁,则返回;
- unlock():释放锁;
链接:http://moguhu.com/article/detail?articleId=26
阅读全文
1 0
- 重入锁--ReentrantLock
- 重入锁--ReentrantLock
- 重入锁ReentrantLock
- 重入锁ReentrantLock
- 重入锁--ReentrantLock
- 重入锁--ReentrantLock
- ReentrantLock 重入锁
- 重入锁ReentrantLock
- ReentrantLock重入锁
- 重入锁--ReentrantLock
- 重入锁ReentrantLock
- ReentrantLock重入锁
- ReentrantLock重入锁
- ReentrantLock(重入锁)以及公平性
- ReentrantLock(重入锁)以及公平性
- ReentrantLock(重入锁)以及公平性
- ReentrantLock(重入锁)以及公平性
- Java重入锁ReentrantLock
- 阿里云上安装rocketMQ
- 【zynq】XDC 书写和使用
- IO流(二)File类
- 网易2018校招内推笔试-交错01串
- 前台CSS样式使用小结
- 重入锁ReentrantLock
- linux下jps报command not found
- 二叉树的遍历
- JS对象简单操作
- 深拷贝构造函数
- leetcode 263. Ugly Number
- 2017"百度之星"程序设计大赛
- Storm架构与运行原理
- 不同的业务逻辑如何发送一个action请求返回不同的数据