Lock、Synchronized锁区别解析( 五 )
可以看到 ,ReetrantLock 有两个构造方法 , 这也是Lock 实现类通有的 , 我们重点看一下第二种构造器 , 因为第一种的实现代码只不过是第二种构造器中代码的一种 。 参数 fair 表示是否是公平锁?如果是 true, 那么创建的 ReetrantLock 对象就是公平锁对象 , 如果 false 或者没有指定参数那么创建出来的对象都是非公平锁对象 。 而 synchronized 只可能是非公平锁 。
常用方法:下面就以ReentranLock 为例 , 说一下lock的常用实现方法 。
1、Lock()lock() 方法其实和 synchronized 的重量级锁执行策略是一样的 , 当然如果在对象创建时指定公平锁 , 那么会直接进入 “等待队列”, 如果没有指定或者是指定为非公平锁那么会先尝试获取锁资源 。 然后没有获取到就会进行一次上下文切换 。
2、tryLock()尝试获取锁资源 , 获取到就直接执行后面的代码并返回 true , 如果没有获取到直接退出不进入 "等待队列" 并返回 false。
3、tryLock(long time,TimeUnit unit)尝试在一段时间内获取锁资源 , 获取到就执行后面的代码并返回 true , 否则退出返回 false。 可以通过 interrupt() 方法中断阻塞状态 。
4、lockInterruptibly()和 lock()一样 , 只不过可以调用该线程的 interrupt() 方法去中断 , 而 Lock() 方法不会被中断 , 只能获取到锁资源的线程调用了 unlock方法才会中断等待状态 。
同步 , 等待通知模型实现同步实现:lock 的加锁的对象就是 lock 本身的对象 , 所以我们只需要调用 lock()方法就可以实现加锁操作 , 但是与 synchronized 不同的是 lock 锁需要手动的去释放 , 也就是调用 unlock() 方法去释放当前对象的锁 , 所以unlock()方法一般是在 finally 修饰的代码块中 , 防止上面发生异常而没有释放锁导致死锁 。
等待-通知模式实现:lock 的 "等待-通知模式" 是通过 Condition 类实现的 , 调用 lock 对象的 newCondition() 方法去创建与之对应的 Condition 对象 , 然后调用 Condition 对象的 await 方法实现阻塞并释放资源给其他线程 , 等到其他线程执行完再调用 Condition 的 signal() 方法(对应Object中的 notify()方法)去随机唤醒一个阻塞的线程 , 而 signalAll()(对应notifyAll())则是唤醒 lock 对象对应的所有阻塞线程 。
下面就用一个例子来实现 。
1 public class lock2{ 23static lock2 ll=new lock2(); 4ReentrantLock lock=new ReentrantLock(); 5Condition cc=lock.newCondition(); 67public static void main(String[] args) { 8new Thread(new qq()).start(); 9new Thread(new qq2()).start();10}11public static class qq implements Runnable{12 13@Override14public void run() {15ll.aa();16}1718}19public static class qq2 implements Runnable{2021@Override22public void run() {23ll.bb();24}2526}2728public void aa() {29lock.lock();30try {31System.out.println("aa方法开始了"+Thread.currentThread().getName());32Thread.sleep(2000);33cc.await();34System.out.println("aa方法结束了"+Thread.currentThread().getName());35} catch (InterruptedException e) {36e.printStackTrace();37}finally {38lock.unlock();39}40}41public void bb() {42lock.lock();43try {44System.out.println("bb方法开始了"+Thread.currentThread().getName());45Thread.sleep(2000);46System.out.println("bb方法结束了"+Thread.currentThread().getName());47cc.signal();48} catch (InterruptedException e) {49e.printStackTrace();50}finally {51lock.unlock();52}53}5455 }
结果:
文章插图
在 "aa方法开始了Thread-0" 输出后 , 等待了两秒后 , 通过 await 方法阻塞当前线程 , 然后把锁资源让给 "Thread-1" , 输出 "bb方法开始了Thread-1", 两秒后再输出 "bb方法结束了Thread-1" , 然后通过signal唤醒 , 因为这里只有一个 "Thread-0" 线程阻塞所以直接唤醒 "Thread-0" , 最后输出 "aa方法结束了Thread-0" 执行完毕 。
ReentrantReadWriteLockReentrantReadWriteLock 是一种特殊的 Lock实现类 , 它除了可以实现上面提到的所有功能外 , 还能实现 "共享锁" 和 "排他锁"。 它的读锁就是 "共享锁", 写锁是 "排他锁"。
共享锁共享锁就是不同线程可以同时执行 , 相当于没有加锁 。 那么问题来了 , 既然多线程可以同时获取共享锁 , 那么共享锁的意义是什么呢?答案就是为了和 "排他锁" 互斥 。 下面先看 ReentrantReadWriteLock 共享锁的例子 。
1 public class Test { 2private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); 34public static void main(String[] args){ 5final Test test = new Test(); 6new Thread(){ 7public void run() { 8test.get(Thread.currentThread()); 9};10}.start();11new Thread(){12public void run() {13test.get(Thread.currentThread());14};15}.start();16}17public void get(Thread thread) {18rwl.readLock().lock();19try {20long start = System.currentTimeMillis();21while(System.currentTimeMillis() - start
- 空调|让格力、海尔都担忧,中国取暖“新潮物”强势来袭,空调将成闲置品?
- 占营收|华为值多少钱
- 俄罗斯手机市场|被三星、小米击败,华为手机在俄罗斯排名跌至第三!
- 页面|如何简单、快速制作流程图?上班族的画图技巧get
- 操盘|中兴统一操盘中兴、努比亚、红魔三大品牌
- 印度|拒绝华为后,印度、英国斥资数十亿求助日本
- 华为|台积电、高通、华为、小米接连宣布!美科技界炸锅:怎么会这样!
- 拍照|iPhone12还没捂热13就曝光了,屏幕、信号、拍照均有升级!
- 路由器|家里无线网经常断网、网速慢怎么办?教你几个小窍门,轻松解决
- 一图看懂!数字日照、新型智慧城市这样建(上篇)|政策解读 | 新型