中国建设银行网站维护,建程网工程找队伍,贵阳企业网站设计制作,一家公司做两个网站Java的synced关键字是一个很棒的工具–它使我们能够以一种简单可靠的方式来同步对关键部分的访问#xff0c;而且也不难理解。 但是有时我们需要对同步进行更多控制。 我们要么需要分别控制访问类型#xff08;读取和写入#xff09;#xff0c;要么使用起来很麻烦#xf… Java的synced关键字是一个很棒的工具–它使我们能够以一种简单可靠的方式来同步对关键部分的访问而且也不难理解。 但是有时我们需要对同步进行更多控制。 我们要么需要分别控制访问类型读取和写入要么使用起来很麻烦因为要么没有明显的互斥锁要么我们需要维护多个互斥锁。 值得庆幸的是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 MapClass? extends Runnable, Lock mLocks new HashMapClass? 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