Java并发教程–重入锁
但是有时我们需要对同步进行更多控制。 我们要么需要分别控制访问类型(读取和写入),要么使用起来很麻烦,因为要么没有明显的互斥锁,要么我们需要维护多个互斥锁。
值得庆幸的是,Java 1.5中添加了锁实用程序类,使这些问题更易于解决。
Java重入锁
Java在java.util.concurrent.locks包中有一些锁实现。
锁的一般类很好地布置为接口:
- 锁 –最简单的锁,可以获取和释放
- ReadWriteLock –具有读和写锁类型的锁实现–一次可以持有多个读锁,除非持有排他写锁
Java提供了我们关心的这些锁的两种实现–两者都是可重入的(这仅意味着线程可以多次重新获取同一锁而没有任何问题)。
- ReentrantLock –如您所料,可重入锁实现
- ReentrantReadWriteLock –可重入ReadWriteLock实现
现在,让我们看一些例子。
读/写锁示例
那么如何使用锁呢? 这很简单:只需获取并发布(永远不要忘记发布-终于是您的朋友!)。
假设我们有一个非常简单的情况,我们需要同步访问一对变量。 一个是简单的值,另一个是根据一些冗长的计算得出的。 首先,这就是我们如何使用synced关键字执行此操作。
public class Calculator {private int calculatedValue;private int value;public synchronized void calculate(int value) {this.value = value;this.calculatedValue = doMySlowCalculation(value);}public synchronized int getCalculatedValue() {return calculatedValue;}public synchronized int getValue() {return value;}
}
很简单,但是如果我们有很多争用或者执行大量读取而写入很少,则同步可能会影响性能。 由于频繁读取比写入频繁得多,因此使用ReadWriteLock可帮助我们最大程度地减少问题:
public class Calculator {private int calculatedValue;private int value;private ReadWriteLock lock = new ReentrantReadWriteLock();public void calculate(int value) {lock.writeLock().lock();try {this.value = value;this.calculatedValue = doMySlowCalculation(value);} finally {lock.writeLock().unlock();}}public int getCalculatedValue() {lock.readLock().lock();try {return calculatedValue;} finally {lock.readLock().unlock();}}public int getValue() {lock.readLock().lock();try {return value;} finally {lock.readLock().unlock();}}
}
该示例实际上显示了使用同步的has的一个大优点:与使用显式锁相比,此方法简洁明了且更加安全。 但是锁提供了使用灵活性,而这是我们以前所没有的。
在上面的示例中,我们可以让数百个线程一次读取相同的值而不会出现问题,并且只有在获得写入锁定时才阻塞读取器。 请记住:许多读取器可以同时获取读取锁定,但是在获取写入锁定时不允许读取器或写入器。
更典型的用途
我们的第一个示例可能会让您感到困惑或不完全相信显式锁是有用的。 难道他们还没有其他用途吗? 当然!
我们在Carfey使用显式锁来解决许多问题。 一个示例是您有可以同时运行的各种任务,但是您不希望同时运行多个相同类型的任务。 一种实现它的干净方法是使用锁。 可以通过同步来完成,但是锁使我们能够在超时后失败。
值得一提的是,您会注意到我们使用了同步锁和显式锁的组合-有时一个比另一个更干净,更简单。
public class TaskRunner {private Map<Class<? extends Runnable>, Lock> mLocks =new HashMap<Class<? extends Runnable>, Lock>();public void runTaskUniquely(Runnable r, int secondsToWait) {Lock lock = getLock(r.getClass());boolean acquired = lock.tryLock(secondsToWait, TimeUnit.SECONDS);if (acquired) {try {r.run();} finally {lock.unlock();}} else {// failure code here}}private synchronized Lock getLock(Class clazz) {Lock l = mLocks.get(clazz);if (l == null) {l = new ReentrantLock();mLocks.put(clazz, l);}return l;}
}
这两个示例应该使您对如何同时使用计划锁和ReadWriteLocks有所了解。 与同步一样,不必担心重新获得相同的锁-JDK中提供的锁是可重入的,因此不会有任何问题。
每当您处理并发时,都有危险。 永远记住以下几点:
- 释放finally块中的所有锁。 这是规则1,有一个原因。
- 当心线程饥饿! 如果您有不想永久等待的许多读者和偶尔的作家,那么ReentrantLocks中的公平设置可能会很有用。 如果其他线程不断持有读取锁,那么编写者可能会等待很长时间(可能永远)。
- 尽可能使用同步。 您将避免错误并保持代码清洁。
- 如果您不希望线程无限期等待获取锁,请使用tryLock() -这类似于数据库具有的等待锁超时。
就是这样! 如果您有任何问题或意见,请随时将其留在下面。
参考: Java并发第2部分–来自我们的JCG合作伙伴的Carent博客上的 Reentrant Locks 。
- Java并发教程–信号量
- Java并发教程–线程池
- Java并发教程–可调用,将来
- Java并发教程–阻塞队列
- Java并发教程– CountDownLatch
- Exchanger和无GC的Java
- Java Fork / Join进行并行编程
- Java最佳实践–队列之战和链接的ConcurrentHashMap
- 使用迭代器时如何避免ConcurrentModificationException
- 改善Java应用程序性能的快速技巧
翻译自: https://www.javacodegeeks.com/2011/09/java-concurrency-tutorial-reentrant.html
Java并发教程–重入锁相关推荐
- java 并发锁_Java并发教程–重入锁
java 并发锁 Java的synced关键字是一个很棒的工具–它使我们可以通过一种简单可靠的方式来同步对关键部分的访问,而且也不难理解. 但是有时我们需要对同步进行更多控制. 我们要么需要分别控制访 ...
- java读写锁死锁例子_Java并发关于重入锁与读写锁的详解
这篇文章主要介绍了Java并发编程之重入锁与读写锁,文中相关实例代码详细,测试可用,具有一定参考价值,需要的朋友可以了解下. 重入锁 重入锁,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对 ...
- Java 中可重入锁、不可重入锁的测试
可重入锁 指在同一个线程在外层方法获取锁的时候,进入内层方法会自动获取锁. 为了避免死锁的发生,JDK 中基本都是可重入锁. 下面我们来测试一下 synchronized 和 java.util.c ...
- Java ReentrantLock可重入锁的源码深度解析
Java的ReentrantLock的源码实现,包括加锁.解锁的源码,以及公平性.重入性的实现! 文章目录 1 ReentrantLock的概述 1.1 ReentrantLock的API方法 1.2 ...
- java中可重入锁的学习总结
2019独角兽企业重金招聘Python工程师标准>>> 经常看到网上的人说,可重入锁一词,但是总是没怎么了解,到底什么是可重入锁,一直是一个模糊的概念,下面来大致总结一下. 可重入锁 ...
- Java并发教程– CountDownLatch
Java中的某些并发实用程序自然会比其他并发实用程序受到更多关注,因为它们可以解决通用问题而不是更具体的问题. 我们大多数人经常遇到执行程序服务和并发集合之类的事情. 其他实用程序不太常见,因此有时它 ...
- Java并发教程–阻塞队列
如第3部分所述,Java 1.5中引入的线程池提供了核心支持,该支持很快成为许多Java开发人员的最爱. 在内部,这些实现巧妙地利用了Java 1.5中引入的另一种并发功能-阻塞队列. 队列 首先,简 ...
- Java并发教程–可调用,将来
从Java的第一个发行版开始,Java的美丽之处之一就是我们可以轻松编写多线程程序并将异步处理引入我们的设计中. Thread类和Runnable接口与Java的内存管理模型结合使用,意味着可以进行简 ...
- Java并发教程–信号量
这是我们将要进行的Java并发系列的第一部分. 具体来说,我们将深入探讨Java 1.5及更高版本中内置的并发工具. 我们假设您对同步和易失性关键字有基本的了解. 第一篇文章将介绍信号量-特别是对信号 ...
最新文章
- video 微信 标签层级过高_基于大数据的用户标签体系建设思路和应用
- PostgreSQL9.5:pg_rewind 快速恢复备节点
- Tomcat、Websphere和Jboss类加载机制
- linux的文件属性和权限学习——分析ls命令结果
- Ubuntu 默认 root 密码修改
- linux .o文件,Linux 文件I/O
- input输入框清除样式
- Nacos配置热更新的4种方式、读取项目配置文件的多种方式,@value,@RefreshScope,@NacosConfigurationProperties
- 2021-01-26
- otl连接mysql数据库_OTL--c++中连接数据库的方法
- W3C 发布 EME 标准,EFF 退出 W3C
- sRGB和scRGB的区别
- 轻松使用Nginx搭建web服务器
- 高并发常见的解决方案
- python 读取行数据_openpyxl读取所有行数据之rows属性
- 使用neon实现RGB888转RGB565
- 【背板子-后缀数组】BZOJ4199 BZOJ4650 LGP5108 CF504E
- 【算法】Bubble Sort(泡式排序)的编程实现思路及其复杂度分析==>冒泡排序
- Vue3通透教程【四】Vue3组合API初体验
- 2023年国开《ERP原理与应用》实验1-5学习行为表现
热门文章
- XML——XML Schema
- etl介绍与etl工具比较_ETL万岁
- apache spark_Apache Spark软件包,从XML到JSON
- jax-rs jax-ws_极端懒惰:使用Spring Boot开发JAX-RS服务
- javadocs_不会吸引人的JavaDocs源样本
- jsp导入jstl标签库_EE JSP:使用JSTL标记库生成动态内容
- Tomcat JDBC池–连接泄漏–捕获罪魁祸首
- .xhr长轮询_使用Spring 3.2的DeferredResult进行长轮询
- Spring JPA数据+Hibernate+ MySQL + Maven
- 类固醇上的Java:5种超级有用的JIT优化技术