Guava-Concurrency

文章目录

  • 概述
  • Synchronizing threads
  • Monitor
    • Monitor explained
    • Monitor best practice
  • ListenableFuture
  • FutureCallback
  • SettableFuture
  • AsyncFunction
  • FutureFallback
  • Futures
  • RateLimiter

概述

在这篇文章中涉及到以下知识点:

  • Monitor类充当Mutex使用,用来确保对代码进行串行访问,非常类似于synchronized关键字,但语义更加简单,并且有一些有用的附加功能。
  • ListenableFuture类的功能与Listenable类在Java中的功能相同,但我们可以注册一个回调方法,以便在Future本身完成之后运行。
  • FutureCallback类允许我们访问Future task的结果,并且允许我们针对成功或失败的场景进行处理。
  • SettableFutureAsyncFunctionFutureFallback类是我们在处理Future实例和进行对象异步转换时非常有用的实用工具类。
  • RateLimiter类是用来限制线程访问资源的频率,它非常类似于一个信号量(semaphore),但是RateLimiter类不是通过线程总数限制访问,而是根据时间限制访问。

Synchronizing threads

虽然Java提供了在程序中运行多个线程的能力,但是有时我们需要限制访问(同步),以便在任何给定的时间只有一个线程可以访问代码的一部分。Java提供了synchronized关键字来实现串行访问的目标。但是使用synchronized有一些问题。首先,如果我们需要在线程上调用wait(),我们必须记住使用while循环:

while(someCondition){
     try {
        wait();
     } catch (InterruptedException e) {
       //In this case we don't care, but we may want
       //to propagate with Thread.interrupt()
     }
}

其次,如果我们有多个条件可以导致线程进入等待状态,那么我们必须调用notifyAll(),因为我们无法针对特定的条件通知线程。使用notifyAll()而不是notify()是不太理想的,因为它会唤醒所有线程来争夺锁,而最终只有一个线程会获得锁。Java 5引入了ReentrantLock类和创建Condition的能力。我们可以通过使用ReentrantLock.newCondition()方法来实现更细粒度控制。现在可以用Condition.signal()调用(类似于notify())唤醒等待特定条件发生的单个线程,尽管有一个Condition.signalAll()方法具有与调用notifyAll()相同的抖动效果。但是我们仍然有一些违反直觉的while循环需要处理:

while(list.isEmpty()){
	Condition.await();
}

幸运的是,Guava有解决这个问题的办法----Monitor

Monitor

针对上面的问题,Guava的Monitor类为我们提供了一种解决方案。它允许多种conditions,并且通过从显式通知系统切换到隐式通知系统,完全消除了通知所有线程的可能性。让我们来看一个例子:

 public class MonitorSample {
       private List<String> list = new ArrayList<String>();
       private static final int MAX_SIZE = 10;
       //创建Monitor实例
       private Monitor monitor = new Monitor();
       //利用Monitor实例构造Guard实例。
       private Monitor.Guard listBelowCapacity = new Monitor.Guard(monitor) {
       	//Guard类有一个抽象的isSatisfied方法,返回值为boolean。(这儿表示如果集合的大小小于10那么就返回true)
           @Override
           public boolean isSatisfied() {
               return list.size() < MAX_SIZE;
           }
	   };
       public void addToList(String item) throws InterruptedException {
       //只有在满足 Guard condition evaluates to true 的时候线程才允许进入
       //enterWhen方法允许线程在满足Guard condition时进入代码块。另外值得注意的是,我们并没有显式地发送任何线程信号;它完全隐含在被满足的Guard condition中。
           monitor.enterWhen(listBelowCapacity);
           try {
               list.add(item);
           } finally {
           //离开时需要释放monitor
               monitor.leave();
           }
	   } 
}

Monitor explained

当一个线程进入一个Monitor块时,它被认为占用了该Monitor实例,并且一旦该线程离开,它就不再占用Monitor块。任何时候只有一个线程可以进入Monitor块。该语义与使用synchronized或ReentrantLocks相同;如果一个线程已经进入Monitor块,那么其他线程必须等到当前线程释放锁,或者通过monitor.leave离开监视器块才能进入Monitor块。同一个线程可以任意次数地进出同一个Monitor块,但是每次进入后面必须跟着一个离开。

Monitor best practice

对于Monitor返回boolean值的方法应该始终被使用在包含包含try/finally块的 if 语句中,以确保线程始终能够退出Monitor块。

if (monitor.enterIf(guardCondition)) {
    try {
        doWork();
    } finally {
        monitor.leave();
    }
}

对于不返回任何值的Monitor方法,方法的调用应该紧跟着try/finally块。

monitor.enterWhen(guardCondition);
try {
     doWork();
} finally {
    monitor.leave()
}

ListenableFuture

FutureCallback

SettableFuture

AsyncFunction

FutureFallback

Futures

RateLimiter

你可能感兴趣的:(guava)