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
- Executor Framework (Item 68)
- 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.
- 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.
Effective Java 69 Prefer concurrency utilities to wait and notify的更多相关文章
- Effective Java 35 Prefer annotations to naming patterns
Disadvantages of naming patterns Typographical errors may result in silent failures. There is no way ...
- Effective Java 53 Prefer interfaces to reflection
Disadvantage of reflection You lose all the benefits of compile-time type checking, including except ...
- Effective Java 68 Prefer executors and tasks to threads
Principle The general mechanism for executing tasks is the executor service. If you think in terms o ...
- Effective Java 18 Prefer interfaces to abstract classes
Feature Interface Abstract class Defining a type that permits multiple implementations Y Y Permitted ...
- Effective Java 20 Prefer class hierarchies to tagged classes
Disadvantage of tagged classes 1. Verbose (each instance has unnecessary irrelevant fields). 2. Erro ...
- Effective Java 25 Prefer lists to arrays
Difference Arrays Lists 1 Covariant Invariant 2 Reified at runtime Erased at run time 3 Runtime type ...
- Effective Java 46 Prefer for-each loops to traditional for loops
Prior to release 1.5, this was the preferred idiom for iterating over a collection: // No longer the ...
- Effective Java 49 Prefer primitive types to boxed primitives
No. Primitives Boxed Primitives 1 Have their own values Have identities distinct from their values 2 ...
- Effective Java Index
Hi guys, I am happy to tell you that I am moving to the open source world. And Java is the 1st langu ...
随机推荐
- Java中基本数据类型的存储方式和相关内存的处理方式(java程序员必读经典)
1.java是如何管理内存的 java的内存管理就是对象的分配和释放问题.(其中包括两部分) 分配:内存的分配是由程序完成的,程序员需要通过关键字new为每个对象申请内存空间(基本类型除外),所有的对 ...
- UNIQUEIDENTIFIER列上的统计信息
UNIQUEIDENTIFIER列上的统计信息非常有意思,在它上面有一些很令人讨厌的行为.我们来看下. 问题重现(The repro) 为了向你展示我们刚抱怨的行为,我用下列简单的表定义创建了一个数据 ...
- Java魔法堂:自定义和解析注解
一.前言 注解(Annotation)作为元数据的载体,为程序代码本身提供额外的信息,使用过MyBatis等ORM框架的朋友对 @Insert 的注解应该不陌生了,这是MyBatis自定义的注解,显然 ...
- Linq专题之Linq查询from子句
Linq查询表达式包含8个常用的子句:from.where.select.join.into.orderby.group.let.我们来看看详细的说明. from: 指定查询操作的 ...
- Xcode配置libdc1394
libdc1394是一个开源库,提供了一个Mac下完整的1394相机编程接口,这篇文章将介绍Xcode如何配置该库. 步骤: 1.下载libdc1394的源码,并解压 http://damien.do ...
- DP入门---Robberies
HDU 2955 Description The aspiring Roy the Robber has seen a lot of American movies, and knows that ...
- 【Asphyre引擎】关于AsphyreTypes中OverlapRect的改动,都是泪啊!!!
OverlapRect改动:两个参数对调了.想问问LP,这样真的好吗? Sphinx304版本的代码: function OverlapRect(const Rect1, Rect2: TRect): ...
- eclipse easyexplorer openexplorer
电脑重装了.. eclipse换成了4.4.2,发现原来的easyexplorer不生效了(原来是4.2),搜了下,换成了open explorer即可. 方式一样,都是丢到eclipse/plugi ...
- 「C语言」文件的概念与简单数据流的读写函数
写完「C语言」单链表/双向链表的建立/遍历/插入/删除 后,如何将内存中的链表信息及时的保存到文件中,又能够及时的从文件中读取出来进行处理,便需要用到”文件“的相关知识点进行文件的输入.输出. 其实, ...
- mvc与三层结构终极区别
http://blog.csdn.net/csh624366188/article/details/7183872 http://www.cnblogs.com/zhhh/archive/2011/0 ...