转载: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. HTML5的新增方法

    json的新增方法: parse()   将JSON转换为字符串:必须是严格的JSON格式: 用法 : var s = {"name":"name"}; JSO ...

  2. PHP是弱类型语言,自动转换,强制转换

    强制转换: (int) - 转换成整型 (bool) - 转换.成布尔型 (float) - 转换成浮点型 (string) - 转换成字符串 (array) - 转换成数组 (object) - 转 ...

  3. CryptoJS DES加密

    <!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equ ...

  4. ML-分类与逻辑回归

    布尔分类(binary classification)问题: 训练集:$S=\{(x^{(i)}, y^{(i)})\}$ 输入:特征向量$x$ 期望输出:$y\in\{0, 1\}$ 这里使用的假设 ...

  5. [转]RAID基础,RAID10与RAID01比较,RAID10与RAID5比较

    原文:http://blog.itpub.net/787018/viewspace-666280/ 文档内容3部分:1.基本的RAID级别介绍2.RAID10和RAID01的比较3.RAID10和RA ...

  6. -[NSBundle initWithURL:]: nil URL argument'

    今天早上同事突然跟我说趣拍的SDK不能用了,一调用就crash,我一听就纳了闷了,原来好好的啊. 然后就开始查呗,马上就要上线了,不搞好,老大会不会杀了我... 搞个全局断点,就停在了一堆我看不懂的界 ...

  7. HDU 5860 Death Sequence(死亡序列)

    p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-s ...

  8. validate插件深入学习-01 小白从看透一个插件开始

    没有编程基础的的我,即使看了一遍jq文档也不知道怎么写程序,一个新的插件看了也不知道怎么用. 总是想做自己会的,自己不会的永远不去触碰,就永远不会. 都说编程这东西,很多都有很像的地方了,一个语言学通 ...

  9. java简单计算器

    写的一个小计算器,留着以后看吧. import java.awt.BorderLayout; import java.awt.Button; import java.awt.Color; import ...

  10. 给博客添加Flash时钟

    依稀记得在cnblogs很多大牛的博客里见到过大牛的新闻公告栏里那种动感十足的Flash时钟控件,先上图: 作为一名刚的接触博客菜鸟,自然免不了一番好奇.博客设置选项里翻来覆去找(以为是cnblogs ...