1 软件包 java.util.concurrent 的描述
1,执行程序
接口。Executor 是一个简单的标准化接口,用于定义类似于线程的自定义子系统,包括线程池、异步 IO 和轻量级任务框架。根据所使用的具体 Executor 类的不同,可能在新创建的线程中,现有的任务执行线程中,或者调用 execute() 的线程中执行任务,并且可能顺序或并发执行。ExecutorService 提供了多个完整的异步任务执行框架。ExecutorService 管理任务的排队和安排,并允许受控制的关闭。ScheduledExecutorService 子接口添加了对延迟的和定期任务执行的支持。ExecutorService 提供了安排异步执行的方法,可执行由 Callable 表示的任何函数,结果类似于 Runnable。Future 返回函数的结果,允许确定执行是否完成,并提供取消执行的方法。
实现。类 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 提供可调的、灵活的线程池。Executors 类提供大多数 Executor 的常见类型和配置的工厂方法,以及使用它们的几种实用工具方法。其他基于 Executor 的实用工具包括具体类 FutureTask,它提供 Future 的常见可扩展实现,以及 ExecutorCompletionService,它有助于协调对异步任务组的处理。
2,队列
java.util.concurrent ConcurrentLinkedQueue 类提供了高效的、可伸缩的、线程安全的非阻塞 FIFO 队列。java.util.concurrent 中的五个实现都支持扩展的 BlockingQueue 接口,该接口定义了 put 和 take 的阻塞版本:LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue、PriorityBlockingQueue 和 DelayQueue。这些不同的类覆盖了生产者-使用者、消息传递、并行任务执行和相关并发设计的大多数常见使用的上下文。
3,并发 Collection
除队列外,此包还提供了几个设计用于多线程上下文中的 Collection 实现:ConcurrentHashMap、CopyOnWriteArrayList 和 CopyOnWriteArraySet。
此包中与某些类一起使用的“Concurrent&rdquo前缀;是一种简写,表明与类似的“同步”类有所不同。例如,java.util.Hashtable 和 Collections.synchronizedMap(new HashMap()) 是同步的,但 ConcurrentHashMap 则是“并发的”。并发集合是线程安全的,但是不受单个排他锁定的管理。在 ConcurrentHashMap 这一特定情况下,它可以安全地允许进行任意数目的并发读取,以及数目可调的并发写入。需要通过单个锁定阻止对集合的所有访问时,“同步”类是很有用的,其代价是较差的可伸缩性。在期望多个线程访问公共集合的其他情况中,通常“并发”版本要更好一些。当集合是未共享的,或者仅保持其他锁定时集合是可访问的情况下,非同步集合则要更好一些。
大多数并发 Collection 实现(包括大多数 Queue)与常规的 java.util 约定也不同,因为它们的迭代器提供了弱一致的,而不是快速失败的遍历。弱一致的迭代器是线程安全的,但是在迭代时没有必要冻结集合,所以它不一定反映自迭代器创建以来的所有更新。
4.1计时
TimeUnit 类为指定和控制基于超时的操作提供了多重粒度(包括纳秒级)。该包中的大多数类除了包含不确定的等待之外,还包含基于超时的操作。在使用超时的所有情况中,超时指定了在表明已超时前该方法应该等待的最少时间。在超时发生后,实现会“尽力”检测超时。但是,在检测超时与超时之后再次实际执行线程之间可能要经过不确定的时间。
4.2同步器
四个类可协助实现常见的专用同步语句。Semaphore 是一个经典的并发工具。CountDownLatch 是一个极其简单但又极其常用的实用工具,用于在保持给定数目的信号、事件或条件前阻塞执行。CyclicBarrier 是一个可重置的多路同步点,在某些并行编程风格中很有用。Exchanger 允许两个线程在集合点交换对象,它在多流水线设计中是有用的。
5,软件包 java.util.concurrent.atomic
类的小工具包,支持在单个变量上解除锁定的线程安全编程。
6,软件包 java.util.concurrent.locks
为锁定和等待条件提供一个框架的接口和类,它不同于内置同步和监视器。
2,自己的一些总结
java.util.concurrent.atomic包
1,线程安全的基础原子类 AtomicBoolean, AtomicInteger, AtomicLong,AtomicIntegerArray,AtomicLongArray,AtomicReference,AtomicReferenceArray
2,*FieldUpdater反射的volatile(不太明白) AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater
3,带版本管理的Reference类 AtomicMarkableReference,AtomicStampedReference
java.util.concurrent.locks包
其实语法自带的synchronized锁在大部分情况下足够用了,比较灵活的场景下才需要使用这些特殊的锁。
1,Lock.java接口
java.util.concurrent包
TimeUnit,计算时间的单位,秒
java的内存模型
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4
4.1 计时、4.2 同步器 的使用
主要包括5个类,Semaphore, CountDownLatch, CyclicBarrier, Exchanger, TimeUnit
Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。例如,下面的类使用信号量控制对内容池的访问
按此方式使用时,二进制信号量具有某种属性(与很多 Lock 实现不同),即可以由线程释放“锁定”,而不是由所有者(因为信号量没有所有权的概念)。在某些专门的上下文(如死锁恢复)中这会很有用。
用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。
例用法: 下面给出了两个类,其中一组 worker 线程使用了两个倒计数锁存器:
第一个类是一个启动信号,在 driver 为继续执行 worker 做好准备之前,它会阻止所有的 worker 继续执行。
第二个类是一个完成信号,它允许 driver 在完成所有 worker 之前一直等待。
class Driver { // ...
void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
另一种典型用法是,将一个问题分成 N 个部分,用执行每个部分并让锁存器倒计数的 Runnable 来描述每个部分,然后将所有 Runnable 加入到 Executor 队列。当所有的子部分完成后,协调线程就能够通过 await。(当线程必须用这种方法反复倒计数时,可改为使用 CyclicBarrier。)
class Driver2 { // ...
void main() throws InterruptedException {
CountDownLatch doneSignal = new CountDownLatch(N);
Executor e = ...
for (int i = 0; i < N; ++i) // create and start threads
e.execute(new WorkerRunnable(doneSignal, i));
doneSignal.await(); // wait for all to finish
}
}
class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final int i;
WorkerRunnable(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}
public void run() {
try {
doWork(i);
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
CyclicBarrier
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。
public class Exchanger<V>extends Object两个线程可以交换对象的同步点。每个线程都在进入 exchange 方法时给出某个对象,并接受其他线程返回时给出的对象。
public enum TimeUnitextends Enum<TimeUnit>TimeUnit 表示给定单元粒度的时间段,它提供在这些单元中进行跨单元转换和执行计时及延迟操作的实用工具方法。
1,
Lock lock = ...;
if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ...
2,
TimeUnit.MILLISECONDS.sleep((long) (Math.random() * 10000)); //thread.sleep的便捷使用
4.1 计时、4.2 同步器 的原理
5,死循环的自旋锁,无锁定的并发
3,一些自测试的代码
测试CyclicBarrier
package com.mike.juc;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
/**
* TODO Comment of CyclicBarrierTest
*/
public class CyclicBarrierTest {
final int N;
final int[][] data;
final CyclicBarrier barrier;
private int[] result;
class Worker implements Runnable {
private int index;
private int[] oneRow;
Worker(int[] data, int index) {
this.index = index;
this.oneRow = data;
}
public void run() {
try {
TimeUnit.MILLISECONDS.sleep((long) (Math.random() * 10000));
// Thread.sleep((long) (Math.random() * 10000));
} catch (InterruptedException e) {
}
System.out.println("start " + index + " row!");
int rowResult = 0;
for (int i = 0, length = oneRow.length; i < length; i++) {
rowResult += oneRow[i];
}
result[index] = rowResult;
try {
System.out.println("finish " + index + " row, result = " + rowResult);
barrier.await();
} catch (InterruptedException ex) {
return;
} catch (BrokenBarrierException ex) {
return;
}
}
}
public CyclicBarrierTest(int[][] matrix) {
data = matrix;
N = matrix.length;
result = new int[N];
barrier = new CyclicBarrier(N, new Runnable() {
public void run() {
int total = 0;
for (int i = 0, length = result.length; i < length; i++) {
total += result[i];
}
System.out.println("total result:" + total);
}
});
}
public void start() {
for (int i = 0; i < N; ++i) {
Thread thread = new Thread(new Worker(data[i], i));
// thread.setDaemon(true);
thread.start();
}
System.out.println("abc");
}
public static void main(String[] args) {
int[][] matrix = { { 1, 2, 3 }, { 2, 3, 4 }, { 3, 4, 5 } };
new CyclicBarrierTest(matrix).start();
}
}
测试Exchanger
package com.mike.juc;
import java.util.concurrent.Exchanger;
/**
* TODO Comment of ExchangerTest
*/
public class ExchangerTest {
Exchanger<String> exchanger = new Exchanger<String>();
class FillingLoop implements Runnable {
public void run() {
String currentBuffer = "123";
System.out.println("===" + Thread.currentThread().getId() + "\tcurrentBuffer="
+ currentBuffer);
try {
currentBuffer = exchanger.exchange(currentBuffer);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("===" + Thread.currentThread().getId() + "\tcurrentBuffer="
+ currentBuffer);
}
}
class EmptyingLoop implements Runnable {
public void run() {
String currentBuffer = "124";
System.out.println(Thread.currentThread().getId() + "\tcurrentBuffer=" + currentBuffer);
try {
currentBuffer = exchanger.exchange(currentBuffer);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId() + "\tcurrentBuffer=" + currentBuffer);
}
}
void start() {
new Thread(new FillingLoop()).start();
new Thread(new EmptyingLoop()).start();
}
public static void main(String[] args) {
new ExchangerTest().start();
}
}
测试 LockSupport,这个类提供了最基本的wait/notify机制。可为各类wait/notify的实现提供基础
package com.mike.juc;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
/**
* TODO Comment of LockSupportTest
*
*/
public class LockSupportTest {
private AtomicBoolean locked = new AtomicBoolean(false);
private Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread>();
public void lock() {
boolean wasInterrupted = false;
Thread current = Thread.currentThread();
waiters.add(current);
// Block while not first in queue or cannot acquire lock
while (waiters.peek() != current || !locked.compareAndSet(false, true)) {
LockSupport.park();
if (Thread.interrupted()) // ignore interrupts while waiting
wasInterrupted = true;
}
waiters.remove();
if (wasInterrupted) // reassert interrupt status on exit
current.interrupt();
}
public void unlock() {
locked.set(false);
LockSupport.unpark(waiters.peek());
}
public static void main(String[] args) {
LockSupportTest lockSupportTest = new LockSupportTest();
for (int i = 0; i < 2; i++) {
new Thread(new Runlock(lockSupportTest), "i=" + i).start();
}
lockSupportTest.unlock();
}
}
class Runlock implements Runnable {
private LockSupportTest lockSupportTest;
/**
* @param lockSupportTest
*/
public Runlock(LockSupportTest lockSupportTest) {
this.lockSupportTest = lockSupportTest;
}
@Override
public void run() {
lockSupportTest.lock();
}
}
测试Object 锁机制:
package com.mike.juc;
import java.util.concurrent.TimeUnit;
/**
* TODO Comment of ObjectTest
*/
public class ObjectTest {
private Object obj = new Object();
public void getAndWait() {
System.out
.println("thread id" + Thread.currentThread().getId() + "\tgetAndWait position 0");
synchronized (obj) {
System.out.println("thread id" + Thread.currentThread().getId()
+ "\tgetAndWait position 1");
try {
obj.wait();
} catch (InterruptedException e) {
}
System.out.println("thread id" + Thread.currentThread().getId()
+ "\tgetAndWait position 2");
}
System.out
.println("thread id" + Thread.currentThread().getId() + "\tgetAndWait position 4");
}
public void notifyOneThread() {
synchronized (obj) {
try {
obj.notify();
System.out.println("thread id" + Thread.currentThread().getId()
+ "\tnotifyOneThread");
} catch (Exception e) {
}
}
}
public static void main(String[] args) throws InterruptedException {
System.err.println("main 1");
ObjectTest objectTest = new ObjectTest();
for (int i = 0; i < 10; i++) {
new Thread(new WaitThread(objectTest)).start();
}
System.err.println("main 2");
TimeUnit.SECONDS.sleep(10l);
System.err.println("main 3");
for (int i = 0; i < 10; i++) {
objectTest.notifyOneThread();
TimeUnit.SECONDS.sleep(1l);
System.err.println("main 3.5");
}
System.err.println("main 4");
}
}
class WaitThread implements Runnable {
private ObjectTest objectTest;
public WaitThread(ObjectTest objectTest) {
this.objectTest = objectTest;
}
@Override
public void run() {
objectTest.getAndWait();
}
}
//从运行结果看,notify的解锁是有序的,先到先解
//main 1
//thread id8 getAndWait position 0
//thread id8 getAndWait position 1
//thread id9 getAndWait position 0
//thread id9 getAndWait position 1
//thread id10 getAndWait position 0
//thread id10 getAndWait position 1
//thread id11 getAndWait position 0
//thread id11 getAndWait position 1
//thread id12 getAndWait position 0
//thread id12 getAndWait position 1
//thread id13 getAndWait position 0
//thread id13 getAndWait position 1
//thread id14 getAndWait position 0
//thread id14 getAndWait position 1
//thread id15 getAndWait position 0
//thread id15 getAndWait position 1
//thread id16 getAndWait position 0
//thread id16 getAndWait position 1
//main 2
//thread id17 getAndWait position 0
//thread id17 getAndWait position 1
//main 3
//thread id1 notifyOneThread
//thread id8 getAndWait position 2
//thread id8 getAndWait position 4
//main 3.5
//thread id1 notifyOneThread
//thread id9 getAndWait position 2
//thread id9 getAndWait position 4
//main 3.5
//thread id1 notifyOneThread
//thread id10 getAndWait position 2
//thread id10 getAndWait position 4
//main 3.5
//thread id1 notifyOneThread
//thread id11 getAndWait position 2
//thread id11 getAndWait position 4
//main 3.5
//thread id1 notifyOneThread
//thread id12 getAndWait position 2
//thread id12 getAndWait position 4
//main 3.5
//thread id1 notifyOneThread
//thread id13 getAndWait position 2
//thread id13 getAndWait position 4
//main 3.5
//thread id1 notifyOneThread
//thread id14 getAndWait position 2
//thread id14 getAndWait position 4
//main 3.5
//thread id1 notifyOneThread
//thread id15 getAndWait position 2
//thread id15 getAndWait position 4
//main 3.5
//thread id1 notifyOneThread
//thread id16 getAndWait position 2
//thread id16 getAndWait position 4
//main 3.5
//thread id1 notifyOneThread
//thread id17 getAndWait position 2
//thread id17 getAndWait position 4
//main 3.5
//main 4
测试 Semaphore
package com.mike.juc;
import java.util.concurrent.Semaphore;
/**
* TODO Comment of Pool
*/
public class Pool {
private static final int MAX_AVAILABLE = 100;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailableItem();
}
public void putItem(Object x) {
if (markAsUnused(x))
available.release();
}
// Not a particularly efficient data structure; just for demo
protected Object[] items = new String[MAX_AVAILABLE];
protected boolean[] used = new boolean[MAX_AVAILABLE];
protected synchronized Object getNextAvailableItem() {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (!used[i]) {
used[i] = true;
return items[i];
}
}
return null; // not reached
}
protected synchronized boolean markAsUnused(Object item) {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (item == items[i]) {
if (used[i]) {
used[i] = false;
return true;
} else
return false;
}
}
return false;
}
}