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. Controller控制器

    控制器概述 上接应用(北向),下接设备(南向),左右扩展(东西接口). 谁掌控了控制器,或者制定了标准,就掌握了SDN. 南向功能:通过Openflow等南向接口技术,对网络设备进行管控,例如拓扑发现 ...

  2. alpha冲6

    队名:日不落战队 安琪(队长) 今天完成的任务 回收站前端界面. 明天的计划 查看个人信息界面. 还剩下的任务 信息修改前端界面. 设置界面. 遇到的困难 模拟机莫名其妙就崩了,调试了很久,后在队友的 ...

  3. CentOS7安装.NET Core运行环境

    安装.NET Core ->首先需要删除以前安装的版本 -> 获取安装脚本 curl -sSL https://raw.githubusercontent.com/dotnet/cli/r ...

  4. Matlab中TCP通讯-实现外部程序提供优化目标函数解

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Matlab中TCP通讯-实现外部程序提供优化目标函数解     本文地址:http://te ...

  5. 【leetcode】62.63 Unique Paths

    62. Unique Paths A robot is located at the top-left corner of a m x n grid (marked 'Start' in the di ...

  6. oracle 不能是用变量来作为列名和表名 ,但使用动态sql可以;

    ORACLE 不能使用变量来作为列名 和表名 一下是个人的一些验证: DECLARE ename1 emp.ename%TYPE ; TYPE index_emp_type ) INDEX BY PL ...

  7. 剖析Vue原理&实现双向绑定MVVM-1

    本文能帮你做什么?1.了解vue的双向数据绑定原理以及核心代码模块2.缓解好奇心的同时了解如何实现双向绑定为了便于说明原理与实现,本文相关代码主要摘自vue源码, 并进行了简化改造,相对较简陋,并未考 ...

  8. js & right click menu

    js & right click menu https://stackoverflow.com/questions/4909167/how-to-add-a-custom-right-clic ...

  9. 【前端学习笔记】JavaScript 常用方法兼容性封装

    获取样式函数封装 function getStyle(ele,attr){ if(ele.currentStyle){ return ele.currentStyle[attr]; } else{ r ...

  10. codeforces 1023 D. Array Restoration 并查集

    D. Array Restoration time limit per test 1 second memory limit per test 256 megabytes input standard ...