synchronized

自从Java提供了多线程编程,我们经常需要处理这样的情况:在特定的时间,我们需要限制访问,确保只有一个线程访问我们的代码。Java提供了同步关键字synchronized来实现这种访问控制,但是使用synchronized会存在一些问题。第一个问题是,当我们需要调用线程的wait()方法时,我们必须记得去使用while循环。看下面例子,来自guava monitor api上的说明:

 public class SafeBox<V> {
private V value; public synchronized V get() throws InterruptedException {
while (value == null) {
wait();
}
V result = value;
value = null;
notifyAll();
return result;
} public synchronized void set(V newValue) throws InterruptedException {
while (value != null) {
wait();
}
value = newValue;
notifyAll();
}
}

在这个例子中获取一个值,当值不存在的时候,我们等待。。。有值的时候需要notifyAll()。这里需要注意的是,我们要在while循环中使用wait方法,而不是if。另外用notifyAll而不是notify。

ReentrantLock

在java.util.concurrent包中提供了ReentrantLock,我们使用它来实现上面的场景看看

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; public class SafeBox<V> {
private final ReentrantLock lock = new ReentrantLock();
private final Condition valuePresent = lock.newCondition();
private final Condition valueAbsent = lock.newCondition();
private V value; public V get() throws InterruptedException {
lock.lock();
try {
while (value == null) {
valuePresent.await();
}
V result = value;
value = null;
valueAbsent.signal();
return result;
} finally {
lock.unlock();
}
} public void set(V newValue) throws InterruptedException {
lock.lock();
try {
while (value != null) {
valueAbsent.await();
}
value = newValue;
valuePresent.signal();
} finally {
lock.unlock();
}
}
}

我们依然需要使用while循环,但是有一个好处,我们可以定义两个Condition,这样我们就可以用signal来替代signalAll,这样可能会带来一点性能上的提升。

Monitor

Monitor是一个支持任意布尔条件的同步的抽象,Monitor类是作为ReentrantLock的一个替代,代码中使用Monitor比使用ReentrantLock更不易出错,可读性也更强,并且也没有显著的性能损失,使用Monitor甚至有潜在的性能得到优化,下面我们看看用guava中的Monitor怎么重写上面的代码

package com.hupengcool.guava.concurrency;

import com.google.common.util.concurrent.Monitor;

public class SafeBox<V> {
private final Monitor monitor = new Monitor();
private final Monitor.Guard valuePresent = new Monitor.Guard(monitor) {
public boolean isSatisfied() {
return value != null;
}
};
private final Monitor.Guard valueAbsent = new Monitor.Guard(monitor) {
public boolean isSatisfied() {
return value == null;
}
};
private V value; public V get() throws InterruptedException {
monitor.enterWhen(valuePresent);
try {
V result = value;
value = null;
return result;
} finally {
monitor.leave();
}
} public void set(V newValue) throws InterruptedException {
monitor.enterWhen(valueAbsent);
try {
value = newValue;
} finally {
monitor.leave();
}
}
}

可以发现使用guava之后,我们不需要使用while,使用Monitor.Guard定义进入代码快的条件即可,代码变得更加容易阅读,写起来也更加方便。

当我们Monitor的方法返回boolean值的时候,我们在if块中包含try-finally块,确保锁能够释放。

if(monitor.enterIf(guard)){
try{
...work..
}finally{
monitor.leave();
}
}else{
.. monitor not available..
}

当monitor的方法不返回任何值的时候,我们的代码也需要在finally中释放锁

monitor.enter()
try{
...work..
}finally{
monitor.leave();
}

Monitor有几个常用的方法

  • enter():进入到当前Monitor,无限期阻塞,等待锁。
  • enter(long time, TimeUnit unit):进入到当前Monitor,最多阻塞给定的时间,返回是否进入Monitor。
  • tryEnter():如果可以的话立即进入Monitor,不阻塞,返回是否进入Monitor。
  • enterWhen(Guard guard):进入当前Monitor,等待Guard的isSatisfied()为true后,继续往下执行 ,但可能会被打断。
  • enterIf(Guard guard):如果Guard的isSatisfied()为true,进入当前Monitor。等待获得锁,不需要等待Guard satisfied。
  • tryEnterIf(Guard guard):如果Guard的isSatisfied()为true并且可以的话立即进入Monitor,不等待获取锁,也不等待Guard satisfied。

Google guava 中的Monitor的更多相关文章

  1. Google Guava中的前置条件

    前置条件:让方法调用的前置条件判断更简单. Guava在Preconditions类中提供了若干前置条件判断的实用方法,我们建议[在Eclipse中静态导入这些方法]每个方法都有三个变种: check ...

  2. google guava cache缓存基本使用讲解

    代码地址:https://github.com/vikde/demo-guava-cache 一.简介 guava cache是google guava中的一个内存缓存模块,用于将数据缓存到JVM内存 ...

  3. Java内存缓存-通过Google Guava创建缓存

    谷歌Guava缓存 Guava介绍 Guava是Google guava中的一个内存缓存模块,用于将数据缓存到JVM内存中.实际项目开发中经常将一些公共或者常用的数据缓存起来方便快速访问. Guava ...

  4. [Google Guava] 2.3-强大的集合工具类:java.util.Collections中未包含的集合工具

    原文链接 译文链接 译者:沈义扬,校对:丁一 尚未完成: Queues, Tables工具类 任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collections包含的工具方法.G ...

  5. [Google Guava] 强大的集合工具类:java.util.Collections中未包含的集合工具

    转载的,有问题请联系我 原文链接 译文链接 译者:沈义扬,校对:丁一 尚未完成: Queues, Tables工具类 任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collecti ...

  6. [转载]Google Guava官方教程(中文版)

      原文链接  译文链接 译者: 沈义扬,罗立树,何一昕,武祖  校对:方腾飞 引言 Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] ...

  7. Google Guava官方教程(中文版)

    Google Guava官方教程(中文版) 原文链接  译文链接 译者: 沈义扬,罗立树,何一昕,武祖  校对:方腾飞 引言 Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库, ...

  8. Guava中Predicate的常见用法

    Guava中Predicate的常见用法 1.  Predicate基本用法 guava提供了许多利用Functions和Predicates来操作Collections的工具,一般在 Iterabl ...

  9. 使用 Google Guava 美化你的 Java 代码

    文章转载自:http://my.oschina.net/leejun2005/blog/172328 目录:[ - ] 1-使用 GOOGLE COLLECTIONS,GUAVA,STATIC IMP ...

随机推荐

  1. lintcode-418-整数转罗马数字

    418-整数转罗马数字 给定一个整数,将其转换成罗马数字. 返回的结果要求在1-3999的范围内. 说明 什么是 罗马数字? https://en.wikipedia.org/wiki/Roman_n ...

  2. Java 线程安全问题

    线程安全问题产生原因: 1.多个线程操作共享的数据: 2.操作共享数据的线程代码有多条.   当一个线程正在执行操作共享数据的多条代码过程中,其它线程也参与了运算, 就会导致线程安全问题的发生. cl ...

  3. Jquery mobile div常用属性

    组件 页面 jQuery Mobile 应用了 HTML5 标准的特性,在结构化的页面中完整的页面结构分为 header. content.footer 这三个主要区域. 在 body 中插入内容块: ...

  4. HDU 2154 跳舞毯

    http://acm.hdu.edu.cn/showproblem.php?pid=2154 Problem Description 由于长期缺乏运动,小黑发现自己的身材臃肿了许多,于是他想健身,更准 ...

  5. $(document).click() 在苹果手机上不能正常运行解决方案

    本来是如下一段跳转代码,发现在安卓和微信开发者工具上都能正常运行,但是苹果手机就不行了. $(document).on('click', '.url', function(){ location.hr ...

  6. js & array to string

    js & array to string https://stackoverflow.com/questions/13272406/convert-string-with-commas-to- ...

  7. 【loj2325】「清华集训 2017」小Y和恐怖的奴隶主 概率dp+倍增+矩阵乘法

    题目描述 你有一个m点生命值的奴隶主,奴隶主受伤未死且当前随从数目不超过k则再召唤一个m点生命值的奴隶主. T次询问,每次询问如果如果对面下出一个n点攻击力的克苏恩,你的英雄期望会受到到多少伤害. 输 ...

  8. 🔺 Garbage Remembering Exam UVA - 11637()

    题目大意:给你N个单词,有两种方法随机排列,一种随机排成一行,另一种随机排成一圈,当两个单词之间的距离在两种排列中都严格小于K时,则这两个单词构成无效单词,问无效单词的期望. 解题思路:首先对于一排单 ...

  9. 【BZOJ3437】小P的牧场(动态规划,斜率优化)

    [BZOJ3437]小P的牧场(动态规划,斜率优化) 题面 BZOJ 题解 考虑暴力\(dp\),设\(f[i]\)表示强制在\(i\)处建立控制站的并控制\([1..i]\)的最小代价. 很显然,枚 ...

  10. 【BZOJ5333】荣誉称号(动态规划)

    [BZOJ5333]荣誉称号(动态规划) 题面 BZOJ 洛谷 题解 今天早上贱狗老师讲的.然而我还是不会. 只好照着\(zsy\)代码大力理解一波. 首先观察等式,如果比较熟悉线段树,会发现就是线段 ...