内部所拥有比较好的性能,但是在灵活性方面有缺陷,并且如果申请锁失败就会陷入阻塞等待的过程中。
对于一些场景,我们可以使用显示锁Lock

基本应用

Lock 的lock方法相当于进入同步块, unlock方法相当于退出同步块。支持跟内部锁同样的重入机制:

    public void displayLock(){Lock lock = new ReentrantLock();lock.lock();try{}finally{lock.unlock();}}public void innerLock(){Object lock = new Object();synchronized (lock){}}

可以看出内部锁的代码还有清爽一点, 显示锁需要在finally中释放

tryLock避免死锁

先看下死锁的情况:

public class TestLock {public static void main(String[] args) {final Accout accout1 = new Accout(20);final Accout accout2 = new Accout(20);final TestLock testLock = new TestLock();new Thread(){@Overridepublic void run() {testLock.transferMoney(accout2, accout1, 10);}}.start();testLock.transferMoney(accout1, accout2, 10);}public void transferMoney(Accout accout1, Accout accout2, int money){synchronized (accout1){try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}synchronized (accout2){accout1.add(money);accout2.decrease(money);System.out.println(accout1.getAccout());System.out.println(accout2.getAccout());}}}
}class Accout{public Accout(int accout){this.accout = accout;}public Lock lock = new ReentrantLock();private int accout;public void add(int money){accout += money;}public void decrease(int money){accout -= money;}public int getAccout() {return accout;}
}

改为不会死锁的情况:

public void transferMoney(Accout accout1, Accout accout2, int money){if(accout1.lock.tryLock()){try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}if(accout2.lock.tryLock()){accout1.add(money);accout2.decrease(money);System.out.println(accout1.getAccout());System.out.println(accout2.getAccout());accout2.lock.unlock();      // sould be in finally block}accout1.lock.unlock();      // sould be in finally block}}

如上其实主要是利用了tryLock当获取不到锁就返回false的特性。另外tryLock还能设置超时时间,指定时间得不到锁才返回false.

tryLock可中断锁

当代码遇到锁标记有很多种选择,获得锁,如果锁不再了等待锁,重入进该锁, 响应中断。
通常的锁在需要等待的时候并不会响应中断。
如下:

public class TestLock {public static void main(String[] args) {new TestLock().testUnInterrupt();}public void testUnInterrupt(){Lock lock = new ReentrantLock();ThreadTest t1 = new ThreadTest(lock, "t1");t1.start();ThreadTest t2 = new ThreadTest(lock, "t2");t2.start();t2.interrupt();}
}class ThreadTest extends Thread{private Lock lock;public ThreadTest(Lock lock, String name){super(name);this.lock = lock;}@Overridepublic void run(){lock.lock();System.out.println(getName() + "运行开始");
//        try {//            lock.lockInterruptibly();
//        } catch (InterruptedException e) {//            System.out.println(getName() + "锁等待被中断");
//            e.printStackTrace();
//        }try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {System.out.println(getName() + "休眠被中断");
//            e.printStackTrace();} finally {lock.unlock();}System.out.println(getName() + "运行完成");}
}

使用lock()的返回结果:

t1运行开始
t2运行开始
t1运行完成
t2休眠被中断
t2运行完成

使用lockInterruptibly()的返回结果:

t1运行开始
t2运行开始
t2锁等待被中断

可见lockInterruptibly与普通锁的区别在于可以在锁等待的时候响应中断

lock和synchronized性能

在JDK6之前性能上Lock要好很多,但是JDK6之后改进了内部锁的算法,现在差不多

公平锁

ReentrantLock锁的构造器中可以选择是否公平,公平的意思就是开始执行的顺序将会按照锁等待的顺序。这样会造成性能下降,只有在对顺序敏感的时候才需要。

synchronized还是ReentrantLock

  • 性能上JDK1.6,ReentrantLock略好。
  • ReentrantLock可以支持复杂的语义。
  • ReentrantLock需要显示关闭
  • synchronized语法上更简单易用
    综上,其实应该更多的使用synchoronized,只有在有必要的时候才使用ReentrantLock

读写锁

普通的锁限制了并发性,对于数据无害的读-读操作也会出现锁竞争。这个时候可以使用读写锁
读写锁的一些特性:
- 基本功能就是有写入的时候要等写完完成才能再执行写入,如果没有写入的时候读是可以并发的
- 可降级不可以升级,就是读解锁前如果获取写锁会死锁,但是写锁中是可以获取读锁的
- 各锁单独可重入
如下:

public class TestLock {public static void main(String[] args) {final Cache cache = new Cache();new Thread(){@Overridepublic void run() {cache.add("1");cache.add("2");cache.add("3");}}.start();new Thread(){@Overridepublic void run() {cache.get();}}.start();new Thread(){@Overridepublic void run() {cache.get();}}.start();}
}class Cache{ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();List<String> datas = new ArrayList<String>();public void add(String data){rwl.writeLock().lock();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}datas.add(data);System.out.println("添加" + data);rwl.writeLock().unlock();}public String get(){rwl.readLock().lock();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}String data = datas.get(0);datas.remove(0);rwl.readLock().unlock();System.out.println("获得" + data);return data;}
}

可以验证写锁互斥,读写并发。

并发编程12-显示锁相关推荐

  1. Java并发编程实战——显示锁

    显示锁 1.1 Lock与ReentrantLocksynchronized 的局限性 与 Lock 的优点 内置锁的局限性:1.无法中断一个正在等待获取锁的线程: 2. 无法在请求获取一个锁时无限地 ...

  2. 并发编程中的锁、条件变量和信号量

    在并发编程中,经常会涉及到锁.条件变量和信号量.本文从并发开始,探究为什么需要它们,它们的概念,实现原理以及应用. 并发简介 并发是指多个事情,在同一时间段内同时发生了.和并发经常一起被提到的是并行. ...

  3. 【并发编程】线程锁--Synchronized、ReentrantLock(可重入锁)

    在说锁之前,我们要明白为什么要加锁,不加锁会怎样? 在并发编程中,很容易出现线程安全问题,接下来我们看个很经典的例子--银行取钱,来看一下有关线程安全的问题. 取钱的流程可以分为一下几个步骤: 1.用 ...

  4. 学习笔记:Java 并发编程④_无锁

    若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 配套资料: ...

  5. Java并发编程,无锁CAS与Unsafe类及其并发包Atomic

    为什么80%的码农都做不了架构师?>>>    我们曾经详谈过有锁并发的典型代表synchronized关键字,通过该关键字可以控制并发执行过程中有且只有一个线程可以访问共享资源,其 ...

  6. Python之路(第三十八篇) 并发编程:进程同步锁/互斥锁、信号量、事件、队列、生产者消费者模型...

    一.进程锁(同步锁/互斥锁) 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理. 例 ...

  7. 教你“强人锁男”——java并发编程的常用锁类型

    Java 并发编程不可不知的七种锁类型与注意事项 锁是java并发编程中最重要的同步机制.锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息.锁是解决并发冲突的重要工具.在开发 ...

  8. 并发编程的悲观锁和乐观锁

    悲观锁和乐观锁 是并发情境下的两种设计思想, 它们的主要区别在于: 悲观锁则认为肯定会发生并发问题, 要么我等着, 要么就让别人等; 乐观锁认为当前发生并发的可能性不大, 我先试试, 不行的话再说. ...

  9. 并发编程-12线程安全策略之常见的线程不安全类

    文章目录 脑图 概述 字符串拼接子之StringBuilder.StringBuffer StringBuilder (线程不安全) StringBuffer (线程安全) 小结 时间相关的类 Sim ...

最新文章

  1. postgresql 编码_开源力量与职业发展 --写给对PostgreSQL有志趣的朋友们
  2. 解决maven cannot change version of project facet dynamic web module to 3.0
  3. 吴恩达《Machine Learning》精炼笔记 4:神经网络基础
  4. C++的最后一道坎|百万年薪的程序员
  5. 今天换了ubuntu10.04
  6. Spring MVC:MySQL和Hibernate的安全性
  7. Java基本语法(14)--for循环结构
  8. java 双循环是如何执行的_java – 双循环赛
  9. 5.Scalal语法03 - 函数
  10. Roberts算子边缘检测原理及实现
  11. C++读写Excel表格教程
  12. Photoshop压缩png图片
  13. 2014.10.6模拟赛【魔兽争霸】
  14. 微信小程序-tab标签栏实现教程
  15. iphone 6 设置自定义铃声(未越狱)
  16. 产品读书《数据产品经理必修课:从零经验到令人惊艳》别读了!!!
  17. 刘彬20000词汇03
  18. 数字电视标准ATSC,DVB的比较
  19. CART分类与回归树的原理与实现
  20. Enhancing Adversarial Training with Second-Order Statistics of Weights

热门文章

  1. LeetCode 421. Maximum XOR of Two Numbers in an Array--Python解法
  2. C++多线程:Linux 线程通信,唤醒,互斥锁(未完待续)
  3. Python字符串转数字
  4. sklearn与pytorch模型的保存与读取
  5. mysql 负载 查看_Mysql-命令查询当前正在负载运行的SQL语句
  6. php程序应用实例,PHP教程.应用实例1_php
  7. ReentrantReadWriteLock
  8. java批量下载文件为zip包
  9. 数据库字符mysql_MySQL数据库之字符函数详解
  10. java 给控件添加边框_Android UI 利用Drawable Shape给控件加边框/立体效果