转载:https://my.oschina.net/realfighter/blog/349924

     https://my.oschina.net/realfighter/blog/349926

Monitor类是作为ReentrantLock的一个替代,代码中使用 Monitor比使用ReentrantLock更不易出错,可读性也更强,并且也没有显著的性能损失,使用Monitor甚至有潜在的性能得到优化。

public abstract static class Guard:一个标识线程是否等待的布尔条件,Guard类总是与单一的Monitor相关联,Monitor可以在任意时间从任意占用Monitor的线程检查Guard,这样代码的编写将不在关心Guard是否被检查的频率。

public abstract boolean isSatisfied():Guard内部提供的抽象方法,isSatisfied(),当被关联的Monitor被占用时,Guard的此方法会被调用,该方法的实现必须取决于被关联Monitor保护的状态,并且状态不可修改。

Monitor有几个常用的方法

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

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

import java.util.concurrent.atomic.AtomicInteger;

/**
* 原文地址:https://gist.github.com/bbejeck/1369371
* User: bbejeck
*/
public class MonitorExample {

private final Monitor monitor = new Monitor();
private volatile boolean condition = true;
private int taskDoneCounter;
//AtomicInteger:线程安全的加减操作
private AtomicInteger taskSkippedCounter = new AtomicInteger(0);
private int stopTaskCount;

private Monitor.Guard conditionGuard = new Monitor.Guard(monitor) {
@Override
public boolean isSatisfied() {
return condition;
}
};

public void demoTryEnterIf() throws InterruptedException {
if (monitor.tryEnterIf(conditionGuard)) {
try {
simulatedWork();
taskDoneCounter++;
} finally {
monitor.leave();
}
} else {
//自增加1
taskSkippedCounter.incrementAndGet();
}
}

public void demoEnterIf() throws InterruptedException {
if (monitor.enterIf(conditionGuard)) {
try {
taskDoneCounter++;
if (taskDoneCounter == stopTaskCount) {
condition = false;
}
} finally {
monitor.leave();
}
} else {
taskSkippedCounter.incrementAndGet();
}

}

public void demoEnterWhen() throws InterruptedException {
monitor.enterWhen(conditionGuard);
try {
taskDoneCounter++;
if (taskDoneCounter == stopTaskCount) {
condition = false;
}
} finally {
monitor.leave();
}
}

private void simulatedWork() throws InterruptedException {
Thread.sleep(250);
}

// public void reEvaluateGuardCondition() {
// monitor.reevaluateGuards();
// }

public int getStopTaskCount() {
return stopTaskCount;
}

public void setStopTaskCount(int stopTaskCount) {
this.stopTaskCount = stopTaskCount;
}

public void setCondition(boolean condition) {
this.condition = condition;
}

public int getTaskSkippedCounter() {
return taskSkippedCounter.get();
}

public int getTaskDoneCounter() {
return taskDoneCounter;
}
}

Test类:

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.lang.reflect.Method;
import java.util.concurrent.*;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

/**
* 原文地址:https://gist.github.com/bbejeck/1369371
* User: bbejeck
*/
public class MonitorExampleTest {

private MonitorExample monitorExample;
private ExecutorService executorService;
private int numberThreads = 10;
// CountDownLatch:同步辅助类,允许一个或多个线程等待其他线程所执行的一组操作完成
private CountDownLatch startSignal;
private CountDownLatch doneSignal;

@Before
public void setUp() throws Exception {
monitorExample = new MonitorExample();
executorService = Executors.newFixedThreadPool(numberThreads);
startSignal = new CountDownLatch(1);
doneSignal = new CountDownLatch(numberThreads);
}

@After
public void tearDown() {
executorService.shutdownNow();
}

/**
* 第一个线程会进入Monitor调用simulatedWork()后线程等待
* 其余9个线程则会进入else,对taskSkippedCounter自增
*
* @throws Exception
*/
@Test
public void testDemoTryEnterIf() throws Exception {
setUpThreadsForTestingMethod("demoTryEnterIf");
startAllThreadsForTest();
waitForTestThreadsToFinish();
int expectedTaskCount = 1;
int expectedSkippedTasks = 9;
assertThat(monitorExample.getTaskDoneCounter(), is(expectedTaskCount));
assertThat(monitorExample.getTaskSkippedCounter(), is(expectedSkippedTasks));
}

/**
* 前5个线程会等待Monitor,因为Guard的isSatisfied()为true
* 但是一旦isSatisfied()变为false,剩余的线程会进入else,
* 对taskSkippedCounter自增
*
* @throws Exception
*/
@Test
public void testDemoEnterIfOnlyFiveTasksComplete() throws Exception {
monitorExample.setStopTaskCount(5);
setUpThreadsForTestingMethod("demoEnterIf");

startAllThreadsForTest();
waitForTestThreadsToFinish();
int expectedTaskCount = 5;
int expectedSkippedTasks = 5;

assertThat(monitorExample.getTaskDoneCounter(), is(expectedTaskCount));
assertThat(monitorExample.getTaskSkippedCounter(), is(expectedSkippedTasks));

}

/**
* 所有10个线程都会进入Monitor,因为在整个时间内Guard的isSatisfied()为true
*
* @throws Exception
*/
@Test
public void testDemoEnterIfAllTasksComplete() throws Exception {
monitorExample.setStopTaskCount(Integer.MAX_VALUE);
setUpThreadsForTestingMethod("demoEnterIf");

startAllThreadsForTest();
waitForTestThreadsToFinish();
int expectedTaskCount = 10;
int expectedSkippedTasks = 0;

assertThat(monitorExample.getTaskDoneCounter(), is(expectedTaskCount));
assertThat(monitorExample.getTaskSkippedCounter(), is(expectedSkippedTasks));

}

/**
* Guard的isSatisfied()初始化为true,但是所有10个线程会进入Monitor
*
* @throws Exception
*/
@Test
public void testDemoEnterWhen() throws Exception {
monitorExample.setStopTaskCount(Integer.MAX_VALUE);
monitorExample.setCondition(false);
setUpThreadsForTestingMethod("demoEnterWhen");
startAllThreadsForTest();
int expectedCompletedCount = 0;
int completedCount = monitorExample.getTaskDoneCounter();
assertThat(completedCount, is(expectedCompletedCount));

monitorExample.setCondition(true);

waitForTestThreadsToFinish();
expectedCompletedCount = 10;
completedCount = monitorExample.getTaskDoneCounter();
assertThat(completedCount, is(expectedCompletedCount));
}

/**
* 在3个线程完成工作后,人为的设置Guard的isSatisfied()为false
* 以证明剩余的7个线程将等待,直到isSatisfied()变为true
* 然后才会进入Monitor.
*
* @throws Exception
*/
@Test
public void testDemoEnterWhenAllTasksCompleteEvenWhenConditionChanges() throws Exception {
monitorExample.setCondition(true);
monitorExample.setStopTaskCount(3);
setUpThreadsForTestingMethod("demoEnterWhen");
startAllThreadsForTest();

//验证最初只有3个线程工作, 重新设定Guard的isSatisfied()为true
FutureTask<Integer> checkInitialTasksCompleted = new FutureTask<Integer>(
new Callable<Integer>() {
public Integer call() {
int initialCompletedTasks = monitorExample.getTaskDoneCounter();
monitorExample.setCondition(true);
// monitorExample.reEvaluateGuardCondition();
return initialCompletedTasks;

}
});

new Thread(checkInitialTasksCompleted).start();

int expectedCompletedCount = 3;
int completedCount = checkInitialTasksCompleted.get();
assertThat(completedCount, is(expectedCompletedCount));

waitForTestThreadsToFinish();
assertThat(completedCount, is(expectedCompletedCount));
expectedCompletedCount = 10;
completedCount = monitorExample.getTaskDoneCounter();
assertThat(completedCount, is(expectedCompletedCount));
}

private void waitForTestThreadsToFinish() throws InterruptedException {
doneSignal.await(1000l, TimeUnit.MILLISECONDS);
}

private void startAllThreadsForTest() {
startSignal.countDown();
}

private Method getMethodUnderTest(String methodName) throws Exception {
return monitorExample.getClass().getDeclaredMethod(methodName);
}


private void setUpThreadsForTestingMethod(String methodName) throws Exception {
final Method testMethod = getMethodUnderTest(methodName);
for (int i = 0; i < numberThreads; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
try {
startSignal.await();
testMethod.invoke(monitorExample);
} catch (Exception e) {
//异常无须处理
} finally {
doneSignal.countDown();
}
}
});
}
}

}

guava学习--monitor的更多相关文章

  1. Guava学习笔记目录

    Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libra ...

  2. guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁

    guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁 1,本文翻译自 http://eclipsesource.com/blogs/2012/06/06/cleaner-code- ...

  3. guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用

    guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用 1,大纲 让我们来熟悉瓜娃,并体验下它的一些API,分成如下几个部分: Introduction Guava Collection ...

  4. Guava学习

    Guava学习笔记目录 Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concu ...

  5. [置顶] Guava学习之ArrayListMultimap

    ArrayListMultimap类的继承关系如下图所示: Guava ArrayListMultimap List Multimap 是一个接口,继承自 Multimap 接口.ListMultim ...

  6. [置顶] Guava学习之Splitter

    Splitter:在Guava官方的解释为:Extracts non-overlapping substrings from an input string, typically by recogni ...

  7. [置顶] Guava学习之Iterators

    Iterators类提供了返回Iterator类型的对象或者对Iterator类型对象操作的方法.除了特别的说明,Iterators类中所有的方法都在Iterables类中有相应的基于Iterable ...

  8. [置顶] Guava学习之Lists

    Lists类主要提供了对List类的子类构造以及操作的静态方法.在Lists类中支持构造ArrayList.LinkedList以及newCopyOnWriteArrayList对象的方法.其中提供了 ...

  9. [置顶] Guava学习之Immutable集合

    Immutable中文意思就是不可变.那为什么需要构建一个不可变的对象?原因有以下几点: 在并发程序中,使用Immutable既保证线程安全性,也大大增强了并发时的效率(跟并发锁方式相比).尤其当一个 ...

随机推荐

  1. 数据持久化以及DAO模式的简单使用

    持久化:(是将程序中的数据在瞬时状态和持久状态间转换机制)        即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘).持久化的主要应用是将内存中的对象存储在关系型的数据库中,当然 ...

  2. android源码中修改wifi热点默认始终开启

    在项目\frameworks\base\wifi\java\android\net\wifi\WifiStateMachine.java里面,有如下的代码,是设置wifi热点保持状态的:如下: pri ...

  3. mongoose操作汇总。嘻嘻

    MongoDb 命令查询所有数据库列表  CODE:  > show dbs 如果想查看当前连接在哪个数据库下面,可以直接输入db CODE:  > db  Admin 想切换到test数 ...

  4. 前端之CSS(一)

    一.什么是CSS CSS是Cascading Style Sheets,层叠样式表,高大上的说法是用来控制网页数据的表现,可以使网页的表现与数据内容分离.通俗来讲,就是用各种盒子的堆叠实现我们想要的H ...

  5. 用kryonet时kryo报buffer underflow错误

    原因是客户端和服务器端的kryo必须register同样的class类,某一端多register一个class类导致的

  6. 【前端】event.target 和 event.currentTarget 的区别

    event.target 和 event.currentTarget 的区别 举例说明: <!DOCTYPE html> <html> <head> <tit ...

  7. 使用rsync和scp远程同步文件

    rsync1. rsync可以通过ssh隧道的方式传输文件夹: rsync -arv --progress clone user@host:remotedir loaldir . rsync通过ssh ...

  8. MYSQL limit,offset 区别

    SELECT keyword FROM keyword_rank WHERE advertiserid' order by keyword LIMIT OFFSET ; 比如这个SQL ,limit后 ...

  9. background-sizi (转)

    http://www.cnblogs.com/greenteaone/archive/2012/08/28/2659878.html  (原创作者链接地址  ) Background-Size:[ & ...

  10. 什么是js和js的基本语法

    时间:2016年12月15日 先讲讲基础语法: 大部分是来操作表单: js动态效果和数据交互(ajax?) js也有自己的API js大部分的DOM操作都是针对input的. 案例学习,对注册页面的简 ...