zoukankan      html  css  js  c++  java
  • Effective Java 69 Prefer concurrency utilities to wait and notify

    Principle

    Use the higher-level concurrency utilities instead of wait and notify for easiness.

    Use ConcurrentHashMap in preference to Collections.synchronizedMap or Hashtable.

    Use concurrent collections in preference to externally synchronized collections.

       

    Three categories of higher-level utilities in java.util.concurrent

    1. Executor Framework (Item 68)
    2. Concurrent collections - provide high- performance concurrent implementations of standard collection interfaces such as List, Queue, and Map.   

      Since all the implementation of Concurrent collections manage their own synchronization internally it's impossible to exclude concurrent activity from a concurrent collection; locking it will have no effect but slow the program.

            // Method simulates the behavior of String.intern. Concurrent canonicalizing map atop ConcurrentMap - faster!

    private static final ConcurrentMap<String, String> map = new ConcurrentHashMap<String, String>();

    public static String intern(String s) {

    String result = map.get(s);

    if (result == null) {

    result = map.putIfAbsent(s, s);

    if (result == null)

    result = s;

    }

    return result;

    }

    Note

    String.intern must use some sort of weak reference to keep from leaking memory over time.

     

    Blocking operation - wait until they can be successfully performed.

    BlockingQueue (Used for work queues) extends Queue and adds several methods, including take, which removes and returns the head element from the queue, waiting if the queue is empty.

    1. Synchronizers - Objects that enable threads to wait for one another.(eg. CountDownLatch, Semaphore, CyclicBarrier and Exchanger).   

      Countdown latches are single-use barriers that allow one or more threads to wait for one or more other threads to do something.

      /**

      * Concurrency timer demo for "69 Prefer concurrency utilities to wait and notify".

      */

      package com.effectivejava.concurrency;

         

      import java.util.concurrent.CountDownLatch;

      import java.util.concurrent.Executor;

      import java.util.concurrent.SynchronousQueue;

      import java.util.concurrent.ThreadPoolExecutor;

      import java.util.concurrent.TimeUnit;

         

      /**

      * @author Kaibo Hao

      *

      */

      public class ExecutorManager {   

      // Simple framework for timing concurrent execution

      public static long time(Executor executor, int concurrency,

      final Runnable action) throws InterruptedException {

      final CountDownLatch ready = new CountDownLatch(concurrency);

      final CountDownLatch start = new CountDownLatch(1);

      final CountDownLatch done = new CountDownLatch(concurrency);

      for (int i = 0; i < concurrency; i++) {

      executor.execute(new Runnable() {

      public void run() {

      ready.countDown(); // Tell timer we're ready

      try {

      start.await(); // Wait till peers are ready

      action.run();

      } catch (InterruptedException e) {

      Thread.currentThread().interrupt();

      } finally {

      done.countDown(); // Tell timer we're done

      }

      }

      });

      }

      ready.await(); // Wait for all workers to be ready

      long startNanos = System.nanoTime();

      start.countDown(); // And they're off!

      done.await(); // Wait for all workers to finish

      return System.nanoTime() - startNanos;

      }

         

      /**

      * @param args

      */

      public static void main(String[] args) {

      try {

      Executor executor = new ThreadPoolExecutor(0, 2, 10,

      TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());

      long executedTime = time(executor, 2, new Runnable() {

      @Override

      public void run() {

      System.out.printf("Runing %s%n", Thread.currentThread());

      }

      });

      System.out.printf("%sns %.3fms %.3fs", executedTime,

      executedTime / 1000.0, executedTime / 1000000.0);

      } catch (InterruptedException e) {

      e.printStackTrace();

      }

      }

      }   

    Note

    If a worker thread catches an InterruptedException, it reasserts the interrupt using the idiom Thread.currentThread().interrupt() and returns from its run method.

    Since System.nanoTime is both more accurate and more precise, and it is not affected by adjustments to the system's real-time clock. For interval timing, always use System.nanoTime in preference to System.currentTimeMillis.   

    Always use the wait loop idiom to invoke the wait method; never invoke it outside of a loop.

    // The standard idiom for using the wait method

    synchronized (obj) {

    while (<condition does not hold>)

    obj.wait(); // (Releases lock, and reacquires on wakeup)   

    ... // Perform action appropriate to condition

    }   

    Reasons a thread might wake up when the condition does not hold:

    • Another thread could have obtained the lock and changed the guarded state between the time a thread invoked notify and the time the waiting thread woke.

    • Another thread could have invoked notify accidentally or maliciously when the condition did not hold. Classes expose themselves to this sort of mischief by waiting on publicly accessible objects. Any wait contained in a synchronized method of a publicly accessible object is susceptible to this problem.

    • The notifying thread could be overly "generous" in waking waiting threads. For example, the notifying thread might invoke notifyAll even if only some of the waiting threads have their condition satisfied.

    • The waiting thread could (rarely) wake up in the absence of a notify. This is known as a spurious wakeup[Posix, 11.4.3.6.1; JavaSE6].

    Summary

    using wait and notify directly is like programming in "concurrency assembly language," as compared to the higher-level language provided by java.util.concurrent. There is seldom, if ever, a reason to use wait and notify in new code. If you maintain code that uses wait and notify, make sure that it always invokes wait from within a while loop using the standard idiom. The notifyAll method should generally be used in preference to notify. If notify is used, great care must be taken to ensure liveness.

       

  • 相关阅读:
    CentOS同步时间
    使用dnsmasq来提升CentOS上网速度
    bash的变量设置
    CentOS找回root密码
    知识学习网站
    webservice接口测试,使用SoapUI工具进行接口测试
    js中字符串转换为数字
    css颜色大全
    Table分页显示调整
    iframe中,页面转换后回到页面的顶部
  • 原文地址:https://www.cnblogs.com/haokaibo/p/prefer-concurrency-utilities-to-wait-and-notify.html
Copyright © 2011-2022 走看看