自食其力,多疑而自信。
速度的提高是以多核处理器的形式而不是更快的芯片的形式出现的。为了使程序运行的更快,你必须学习如何利用这些额外的处理器,而这正是并发赋予你的能力。
public class LearnConcurrency implements Runnable {
protected int countDown = 10;
private static int taskCount = 0;
// final初始化后,不希望被修改
private final int id = taskCount++;
public LearnConcurrency(){}
public LearnConcurrency(int countDown) {
this.countDown = countDown;
}
public String status() {
return "#" + id + "(" + (countDown >0 ?countDown :"Liftoff!") +"),";
}
public void run() {
while (countDown-- > 0) {
System.out.print(status());
// 对线程调度器建议:我已经执行完生命周期中最重要的部分了,此刻正是切换给其他任务执行一段时间的大好时机
Thread.yield();
}
}
}
Thread.yield()
对线程调度器建议:我已经执行完生命周期中最重要的部分了,此刻正是切换给其他任务执行一段时间的大好时机要实现线程行为,必须显式地将一个任务附着到线程上,传统方式是把它提交给Thread构造器。
```java
public class BasicThread {
public static void main(String[] args) {
Thread thread = new Thread(new LearnConcurrency());
thread.start();
System.out.println("Waiting for LiftOff");
}
}
```
上面的代码运行后有两个线程两个方法在运行,main和run。
```java
public class CachedThreadPool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
executorService.execute(new LearnConcurrency());
}
executorService.shutdown();
}
```
经常使用单个的Executor创建和管理系统中所有的任务。
```java
public class CachedThreadPool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
executorService.execute(new LearnConcurrency());
}
executorService.shutdown();
}
}
```
SingleThreadExecutor用于希望在另一个线程中连续运行的任何事物(长期存活的任务)。例如监听进入的套接字连接的任务(他只有一个线程)。
```java
public class SingleThreadExecutor {
public static void main(String[] args) {
ExecutorService executorService =
Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
executorService.execute(new LearnConcurrency());
}
executorService.shutdown();
}
}
```
它的类型参数表示的是从方法call()(而不是run())中返回的值。
```java
public class TaskWithResult implements Callable {
private int id;
public TaskWithResult(int id) {
this.id = id;
}
@Override
public String call() throws Exception {
return "result of TaskWithResult " + id;
}
}
@Test
public void test1() {
ExecutorService executorService = Executors.newCachedThreadPool();
ArrayList> results =
new ArrayList<>();
for (int i = 0; i < 10; i++) {
results.add(executorService.submit(new TaskWithResult(i)));
}
for (Future future:
results) {
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
```
executorService.submit(new TaskWithResult());
返回future
对象,Futrue可以监视目标线程调用call的情况,当你调用Future的get()方法以获得结果时,当前线程就开始阻塞,直到call方法结束返回结果。main()就是一个非后台线程。
```java
public class SimpleDaemons implements Runnable {
@Override
public void run() {
try {
while (true) {
TimeUnit.MICROSECONDS.sleep(1000);
System.out.println(Thread.currentThread() + " " + this);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
Thread daemon = new Thread(new SimpleDaemons());
daemon.setDaemon(true);
daemon.start();//必须在线程启动之前设置为后台线程
}
System.out.println("main over");
}
}
```
结果
```
Thread[Thread-4,5,main] cn.learn.concurrency.SimpleDaemons@30f51e1e
Thread[Thread-0,5,main] cn.learn.concurrency.SimpleDaemons@4b7137c1
Thread[Thread-2,5,main] cn.learn.concurrency.SimpleDaemons@7b293431
Thread[Thread-1,5,main] cn.learn.concurrency.SimpleDaemons@20ff4faa
main over
Thread[Thread-1,5,main] cn.learn.concurrency.SimpleDaemons@20ff4faa
Thread[Thread-2,5,main] cn.learn.concurrency.SimpleDaemons@7b293431
Thread[Thread-4,5,main] cn.learn.concurrency.SimpleDaemons@30f51e1e
Thread[Thread-0,5,main] cn.learn.concurrency.SimpleDaemons@4b7137c1
Thread[Thread-1,5,main] cn.learn.concurrency.SimpleDaemons@20ff4faa
Thread[Thread-2,5,main] cn.learn.concurrency.SimpleDaemons@7b293431
Thread[Thread-4,5,main] cn.learn.concurrency.SimpleDaemons@30f51e1e
Thread[Thread-0,5,main] cn.learn.concurrency.SimpleDaemons@4b7137c1
Thread[Thread-4,5,main] cn.learn.concurrency.SimpleDaemons@30f51e1e
Thread[Thread-0,5,main] cn.learn.concurrency.SimpleDaemons@4b7137c1
Thread[Thread-6,5,main] cn.learn.concurrency.SimpleDaemons@42f5503f
Thread[Thread-2,5,main] cn.learn.concurrency.SimpleDaemons@7b293431
```
一个后台线程产生工厂
```java
public class DaemonThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
}
}
```
finally子句根本不会执行,但是如果去掉setDaemon()的调用,就会看到finally子句将会执行。
```java
class ADaemon implements Runnable {
@Override
public void run() {
try {
System.out.println("Starting ADemon");
TimeUnit.MICROSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("run finally");
}
}
}
public class DaemonsDontRunFinally {
public static void main(String[] args) {
Thread thread = new Thread(new ADaemon());
thread.setDaemon(true);
thread.start();
}
}
```
public class SelfManaged implements Runnable {
private int countDown = 5;
private Thread thread = new Thread(this);
public SelfManaged() {
thread.start();
}
@Override
public String toString() {
return Thread.currentThread().getName() + "(" +countDown + "),";
}
@Override
public void run() {
while (true) {
System.out.println(this);
if (--countDown == 0) {
return;
}
}
}
}
在t中调用interrupt()可以中断
class Sleeper extends Thread {
private int duration;
public Sleeper(String name,int sleepTime) {
super(name);
duration = sleepTime;
start();
}
@Override
public void run() {
try {
sleep(duration);
} catch (Exception e) {
System.out.println(getName() + " was interrupted. " + "isInterrupted():" + isInterrupted());
return;
}
}
}
class Joiner extends Thread{
private Sleeper sleeper;
public Joiner (String name,Sleeper sleeper) {
super(name);
this.sleeper = sleeper;
start();
}
@Override
public void run() {
try {
sleeper.join();
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
System.out.println(getName() + " join completed");
}
}
public class Joining {
public static void main(String[] args) {
Sleeper
sleeper = new Sleeper("Sleepy",1500),
grumpy = new Sleeper("grumpy",1500);
Joiner
joiner = new Joiner("Dopey",sleeper),
doc = new Joiner("Doc",grumpy);
grumpy.interrupt();
}
}
多线程简单应用–创建有响应的用户界面
```
class UnResponseUI {
private volatile double d = 1;
public UnResponseUI() throws IOException {
while (d > 0) {
d = d + (Math.PI + Math.E) / d;
}
System.in.read();
}
}
public class ResponseUI extends Thread {
private static volatile double d = 1;
public ResponseUI() {
setDaemon(true);
start();
}
@Override
public void run() {
while (true) {
d = d + (Math.PI + Math.E) / d;
}
}
public static void main(String[] args) throws IOException {
new ResponseUI();
System.in.read();
System.out.println(d);
}
}
```
继续错误的代价由别人来承担,而承认错误的代价由自己承担。
Thread.UncaughtExceptionHandler.uncaughtException()
会在线程,因为未捕获的异常而临近死亡时被调用。使用方法是在要捕获异常的Thread对象上附着一个Thread.UncaughtExceptionHandler
。thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler())
```java
class ExceptionThread2 implements Runnable{
@Override
public void run() {
Thread thread = Thread.currentThread();
System.out.println("run() by " + thread);
System.out.println("eh = " + thread.getUncaughtExceptionHandler());
throw new RuntimeException();
}
}
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("caught " + e);
}
}
class HandlerThreadFactory implements ThreadFactory {
// 生产带有MyUncaughtExceptionHandler的Thread
@Override
public Thread newThread(Runnable r) {
System.out.println(this + " creating new Thread");
Thread thread = new Thread(r);
System.out.println("created " + thread);
thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
System.out.println("eh = " + thread.getUncaughtExceptionHandler());
return thread;
}
}
public class CaptureUncaughtException {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool(new HandlerThreadFactory());
executorService.execute(new ExceptionThread2());
}
}
```
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler())
设置默认的未捕获异常处理器
。boolean类型的变量是原子性,意味着诸如赋值和返回值这样的简单操作在发生时没有中断的可能,所以看不到这个域处于执行这些简单操作的过程中的中间状态。
synchronized
的形式,为防止资源冲突提供内置支持。使用显式的Lock对象
```java
public int next() {
lock.lock();
try {
//一系列操作
} finally {
lock.unlock();
}
}
```
lock()
和unlock()
管理临界资源,这样做的优势是方便还有就是可以管理异常。tryLock()
,这样的好处是,try一下,如果不行,接着去离开执行其他一些事情,而不是等待。一个方法中的一段代码被称为临界区。
- 也是使用synchronized关键字
```java
synchronized(syncObject) {
//This code can be accessed
//by only one task at a time
}
```
- 进入此临界区之前必须得到syncObjec对象的锁。如果得不到,就需要等到锁被释放以后,才能进入临界区。
- 设计模式——模板方法:某个类的一些功能在基类中实现,并且其一个或多个抽象方法在派生类中定义(使用abstract类)。
- 宁愿使用同步控制块而不是对整个方法进行同步控制的典型原因:是的其他线程能更多的访问(在安全的情况下尽可能多)
synchronized块必须给定一个在其上进行同步的对象,并且最合理的方式就是,使用其方法正在被调用的当前对象:synchronized(this),一旦获取到synchronized锁,那么该对象其他的synchronized方法和临界区就不能被调用了。
class DualSynch {
private Object object = new Object();
public synchronized void f() {
for (int i = 0;i < 10000; i++) {
System.out.println("f()");
Thread.yield();
}
}
public void g() {
synchronized (object) {
for (int i =0;i < 10000;i++) {
System.out.println("g()");
Thread.yield();
}
}
}
}
public class SyncObject {
public static void main(String[] args) {
final DualSynch dualSynch = new DualSynch();
new Thread() {
public void run() {
dualSynch.f();
}
}.start();
dualSynch.g();
}
}
private static ThreadLocal value = new ThreadLocal(){private Random rand = new Random(47);protected synchronized Integer initialValue() {return rand,nextInt(10000);}};
```java
class Count {
private int count = 0;
private Random random = new Random(47);
public synchronized int increment() {
int temp = count;
if (random.nextBoolean()) {
Thread.yield();
}
return (count = ++temp);
}
public synchronized int value() {
return count;
}
}
class Entrance implements Runnable {
private static Count count = new Count();
private static List entranceList =
new ArrayList<>();
private int number = 0;
private final int id;
private static volatile boolean canceled = false;
public static void cancel() {
canceled = true;
}
public Entrance(int id) {
this.id = id;
entranceList.add(this);
}
@Override
public void run() {
while (!canceled) {
synchronized (this) {
++number;
}
System.out.println(this + " Total: " + count.increment());
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
System.out.println("sleep interrupted");
}
}
System.out.println("Stopping " + this);
}
public synchronized int getValue() {
return number;
}
@Override
public String toString() {
return "Entrance " + id + ": " + getValue();
}
public static int getTotalCount() {
return count.value();
}
public static int sumEntrances() {
int sum = 0;
for (Entrance entrance:
entranceList) {
sum += entrance.getValue();
}
return sum;
}
}
public class OrnamentalGarden {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
executorService.execute(new Entrance(i));
}
TimeUnit.SECONDS.sleep(3);
Entrance.cancel();
executorService.shutdown();
if (!executorService.awaitTermination(250,TimeUnit.MICROSECONDS)) {
System.out.println("Some tasks were not terminated!");
}
System.out.println("Total: " + Entrance.getTotalCount());
System.out.println("Sum of Entrances: " + Entrance.sumEntrances());
}
}
```
- 这里使用了单个的Count对象,来跟踪花园参观者的数量(将Count当做一个静态域储存)。
- Count.increment()和Count.value()都是synchronized的,用来控制对count域的访问。
- 每个Entrance任务都维护着一个本地值,它包含通过某个特定入口进入的参观者的数量。
- 因为Entrance.canceled是一个volatile布尔标志,而它只会被读取和赋值(不会与其他域组合在一起被读取),所以不需要同步对其的访问就可以安全地操作它。
- 在3秒钟之后,main()向Entrance发送static cancel()消息,然后调用executorService对象的shutdown(),之后调用executorService.awaitTermination()方法,它会等待每个任务结束,如果所有任务在超时时间达到之前全部结束,则返回true,否则返回false。但这并不意味着Entrance对象是无效的,所以依然可以操作List。
惯用法
```java
class NeedsCleanUp {
private final int id;
public NeedsCleanUp(int id) {
this.id = id;
}
public void cleanup() {
System.out.println("Cleaning up:" + id);
}
}
class Blocked3 implements Runnable {
private volatile double aDouble = 0.0;
@Override
public void run() {
while (!Thread.interrupted()) {
NeedsCleanUp needsCleanUp = new NeedsCleanUp(1);
try {
System.out.println("Sleeping");
TimeUnit.SECONDS.sleep(1);
NeedsCleanUp needsCleanUp1 = new NeedsCleanUp(2);
try {
System.out.println("Calculating");
for (int i = 1; i < 2500000; i++) {
aDouble = aDouble + (Math.PI + Math.E) / aDouble;
System.out.println("Finished time-consuming operation");
}
} finally {
needsCleanUp1.cleanup();
}
} catch (InterruptedException e) {
System.out.println("");
} finally {
needsCleanUp.cleanup();
}
}
System.out.println("Exiting via while() test");
}
}
public class InterruptingIdiom {
public static void main(String[] args) throws InterruptedException {
if (args.length != 1) {
System.out.println("usage java InterruptingIdiom delay--in-mS");
System.exit(1);
}
Thread thread = new Thread(new Blocked3());
thread.start();
TimeUnit.MILLISECONDS.sleep(new Integer(args[0]));
thread.interrupt();
}
}
```
通常这个条件将由另一个任务来改变。
忙等待:任务测试这个条件的同时,不断地进行空循环。
wait()不会进行愚蠢的忙等待,她在等待外界条件的变化的时候会将任务挂起,并且只有notify()或者notifyAll(),这时候任务被唤醒并且检查条件产生变化了没有
调用wait就意味着:
我已经刚刚做完能做的所有事情,因此我要在这里等待。但是我希望其他的synchronized操作在条件合适的情况下能够执行。
经常的用法wait(不加参数),即无限期的等下去,知道notify,notifyAll消息。
一般这些方法都只在同步代码块中使用。
```java
class Car {
private boolean waxOn = false;
public synchronized void waxed() {
waxOn = true;
notifyAll();
}
public synchronized void buffed() {
waxOn = false;
notifyAll();
}
public synchronized void waitForWaxing() throws InterruptedException {
while (waxOn == false) {
wait();
}
}
public synchronized void waitForBuffed() throws InterruptedException {
while (waxOn == true) {
wait();
}
}
}
class WaxOn implements Runnable {
private Car car;
public WaxOn(Car car) {
this.car = car;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
System.out.println("Wax On!");
TimeUnit.MILLISECONDS.sleep(200);
car.waxed();
car.waitForBuffed();
}
} catch (InterruptedException e) {
System.out.println("Exiting via interrupt");
}
System.out.println("Ending Wax On task");
}
}
class WaxOff implements Runnable {
private Car car;
public WaxOff(Car car) {
this.car = car;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
car.waitForWaxing();
System.out.println("Wax Off! ");
TimeUnit.MILLISECONDS.sleep(200);
car.buffed();//任务被挂起并释放当前对象的锁
}
} catch (InterruptedException e) {
System.out.println("Exiting via interrupt! ");
}
System.out.println("Ending Wax Off task");
}
}
public class WaxOMatic {
public static void main(String[] args) throws InterruptedException {
Car car = new Car();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new WaxOff(car));
executorService.execute(new WaxOn(car));
TimeUnit.SECONDS.sleep(5);
executorService.shutdownNow();
}
}
```
本质就是检查所感兴趣的特定条件,并在条件不满足的情况下返回到wait,惯用法就是使用while来编写这种代码。
```java
// T1
synchronized (sharedMonitor) {
;
sharedMonitor.notify();
}
// T2
while (someCondition) {
// Point1
synchronized (sharedMonitor) {
sharedMonitor.wait();
}
}
```
修改方案:防止在someCondition变量上产生竞争条件
```java
// T2
synchronized (sharedMonitor) {
while (someCondition) {
sharedMonitor.wait();
}
}
```
notifyAll是当因为某个特定锁而被调用时,只有等待这个锁的任务才会被唤醒。
```java
class Blocker {
synchronized void waitingCalling() {
try {
while (!Thread.interrupted()) {
wait();
System.out.println(Thread.currentThread() + " ");
}
} catch (InterruptedException e) {
// OK to exit this way
}
}
synchronized void prod() {notify();}
synchronized void prodAll() {notifyAll();}
}
class Task implements Runnable {
static Blocker blocker = new Blocker();
@Override
public void run() {
blocker.waitingCalling();
}
}
class Task2 implements Runnable {
static Blocker blocker = new Blocker();
@Override
public void run() {
blocker.waitingCalling();
}
}
public class NotifyVsNotifyAll {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService =
Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
executorService.execute(new Task());
}
executorService.execute(new Task2());
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
boolean prod = true;
@Override
public void run() {
if (prod) {
System.out.println("\nnotify() ");
Task.blocker.prod();//不会影响Task2的唤醒
prod = false;
} else {
System.out.println("\nnotifyAll() ");
Task.blocker.prodAll();//不会影响Task2的唤醒
prod = true;
}
}
},400,400);//run every .4 second
TimeUnit.SECONDS.sleep(5);
timer.cancel();
System.out.println("\nTimer canceled");
TimeUnit.MILLISECONDS.sleep(500);
System.out.println("\nShutting down");
executorService.shutdownNow();
}
}
```
```java
class Meal {
private final int orderNum;
public Meal(int orderNum) {
this.orderNum = orderNum;
}
@Override
public String toString() {
return "Meal " + orderNum;
}
}
class WaitPerson implements Runnable {//服务员
private Restaurant restaurant;
public WaitPerson(Restaurant restaurant) {
this.restaurant = restaurant;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (this) {
while (restaurant.meal == null) {
wait();//...for the chef to 做这个食物
}
}
System.out.println("-Wait person got " + restaurant.meal);
synchronized (restaurant.chef) {
restaurant.meal = null;
restaurant.chef.notifyAll();// Ready for another
}
}
} catch (InterruptedException e) {
System.out.println("WaitPerson interrupted");
}
}
}
class Chef implements Runnable {
private Restaurant restaurant;
private int count = 0;
public Chef(Restaurant restaurant) {
this.restaurant = restaurant;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (this) {
while (restaurant.meal != null) {
wait();//...for the meal to 被端走
}
}
if (++count == 10) {
System.out.println("Out of food, closing");
restaurant.exec.shutdownNow();
}
System.out.println("Order up ! ");
synchronized (restaurant.waitPerson) {
restaurant.meal = new Meal(count);
restaurant.waitPerson.notifyAll();
System.out.println("-");
}
TimeUnit.MILLISECONDS.sleep(100);
}
} catch (InterruptedException e) {
System.out.println("Chef interrupted");
}
}
}
public class Restaurant {
Meal meal;
ExecutorService exec = Executors.newCachedThreadPool();
WaitPerson waitPerson = new WaitPerson(this);
Chef chef = new Chef(this);
public Restaurant() {
exec.execute(chef);
exec.execute(waitPerson);
}
public static void main(String[] args) {
new Restaurant();
}
}
```
- Chef厨师和waitPerson服务员,之间是生产者与消费者的关系。Restaurant是两者的焦点。
- 在run中,服务员进入wait模式,停止其任务,直至被Chef的notifyAll唤醒。
- 一旦Chef送上Meal并通知WaitPerson,这个Chef就将等待,直至WaitPerson收集到订单并通知Chef,之后Chef就可以做下一份订单了。
- 有一个问题:在并发应用中,某个其他的任务可能会在WaitPerson被唤醒时,会突然插足(调度器调度问题)并拿走订单,唯一安全的方式是使用下面这种wait惯用法(当然要在恰当的同步内部,并采用防止错失信号可能性的程序设计):
```java
while(conditionIsNotMet(不满足的条件//意味着满足了条件就不等待了))
wait();
```
-
使用互斥并允许任务挂起的基本类是Condition,可以调用其await来挂起一个任务,当外部条件变化,可以使用signal来通知这个任务,从而唤醒一个任务,也可以使用signalAll唤醒所有在这个Condition上被其自身挂起的任务(比notifyAll更安全)。
```java
class Car {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean waxOn = false;
public void waxed() {
lock.lock();
try {
waxOn = true;
condition.signalAll();
} finally {
lock.unlock();
}
}
public void buffed() {
lock.lock();
try {
waxOn = false;
condition.signalAll();
} finally {
lock.unlock();
}
}
public void waitForWaxing() throws InterruptedException {
lock.lock();
try {
while (waxOn == false) {
condition.await();
}
} finally {
lock.unlock();
}
}
public void waitForBuffing() throws InterruptedException {
lock.lock();
try {
while (waxOn == true) {
condition.await();
}
} finally {
lock.unlock();
}
}
}
class WaxOn implements Runnable {
private Car car;
public WaxOn(Car car) {
this.car = car;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
System.out.println("WaxOn! ");
TimeUnit.MILLISECONDS.sleep(200);
car.waxed();
car.waitForBuffing();
}
} catch (InterruptedException e) {
System.out.println("Exiting via interrupt");
}
System.out.println("Ending Wax On task");
}
}
class WaxOff implements Runnable {
private Car car;
public WaxOff(Car car) {
this.car = car;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
car.waitForWaxing();
System.out.println("Wax Off! ");
TimeUnit.MILLISECONDS.sleep(200);
car.buffed();
}
} catch (InterruptedException e) {
System.out.println("Exiting via interrupt");
}
System.out.println("Ending Wax Off task");
}
}
public class WaxOMatic2 {
public static void main(String[] args) throws InterruptedException {
Car car = new Car();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new WaxOff(car));
executorService.execute(new WaxOn(car));
TimeUnit.SECONDS.sleep(5);//让他工作5秒,因为WaxOff和WaxOn中的run都有while(!Thread.interrupted){}
executorService.shutdownNow();
}
}
```
wait和notifyAll以一种非常低级的方式解决了任务互操作问题,即每次交互时都握手。在许多情况下,你应该瞄向更高的抽象级别,即使用同步队列来解决任务协作问题,同步队列在任何时刻都只允许一个任务插入或移除元素。有java.util.concurrent.BlockingQueue接口中提供了这个队列,常用的有LinkedBlockingQueue,ArrayBlockingQueue。
class Toast {
public enum Status {DRY, BUTTERED, JAMMED}
private Status status = Status.DRY;
private final int id;
public Toast(int id) {
this.id = id;
}
public void butter() {
status = Status.BUTTERED;
}
public void jam() {
status = Status.JAMMED;
}
public Status getStatus() {
return status;
}
public int getId() {
return id;
}
@Override
public String toString() {
return "Toast{" +
"status=" + status +
", id=" + id +
'}';
}
}
class ToastQueue extends LinkedBlockingDeque{}
class Toaster implements Runnable {
private ToastQueue toastQueue;
private int count = 0;
private Random random = new Random(47);
public Toaster(ToastQueue toastQueue) {
this.toastQueue = toastQueue;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
TimeUnit.MILLISECONDS.sleep(100 + random.nextInt(500));
// Make toast
Toast toast = new Toast(count++);
System.out.println(toast);
// Insert into queue
toastQueue.put(toast);
}
} catch (InterruptedException e) {
System.out.println("Toaster interrupted! ");
}
System.out.println("Toaster off");
}
}
//apply butter to toast
class Butterer implements Runnable {
private ToastQueue dryQueue,butteredQueue;
public Butterer(ToastQueue dryQueue, ToastQueue butteredQueue) {
this.dryQueue = dryQueue;
this.butteredQueue = butteredQueue;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
// Blocks until next toast is available
Toast toast = dryQueue.take();
toast.butter();
System.out.println(toast);
butteredQueue.put(toast);
}
} catch (InterruptedException e) {
System.out.println("Butterer interrupted");
}
System.out.println("Butterer off");
}
}
//apply jam to buttered toast
class Jammer implements Runnable {
private ToastQueue butteredQueue,finishedQueue;
public Jammer(ToastQueue butteredQueue, ToastQueue finishedQueue) {
this.butteredQueue = butteredQueue;
this.finishedQueue = finishedQueue;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
// blocks until next piece of toast is available;
Toast toast = butteredQueue.take();
toast.jam();
System.out.println(toast);
finishedQueue.put(toast);
}
} catch (InterruptedException e) {
System.out.println("Jammer interrupted");
}
System.out.println("Jammer off");
}
}
//Consume the toast
class Eater implements Runnable {
private ToastQueue finishedQueue;
private int counter = 0;
public Eater(ToastQueue finishedQueue) {
this.finishedQueue = finishedQueue;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
// Blocks until next toast is available;
Toast toast = finishedQueue.take();
if (toast.getId() != counter++ || toast.getStatus() != Toast.Status.JAMMED) {
System.out.println(">>>>>> Error: " + toast);
System.exit(1);
} else {
System.out.println("Chomp! " + toast);
}
}
} catch (InterruptedException e) {
System.out.println("Eater interrupted");
}
System.out.println("Eater off");
}
}
public class ToastOMatic {
public static void main(String[] args) throws InterruptedException {
ToastQueue dryQueue = new ToastQueue(),
butteredQueue = new ToastQueue(),
finishedQueue = new ToastQueue();
ExecutorService executorService =
Executors.newCachedThreadPool();
executorService.execute(new Toaster(dryQueue));
executorService.execute(new Butterer(dryQueue,butteredQueue));
executorService.execute(new Jammer(butteredQueue,finishedQueue));
executorService.execute(new Eater(finishedQueue));
TimeUnit.SECONDS.sleep(5);
executorService.shutdownNow();
}
}
提供线程功能的类库就以“管道”的形式对线程间的输入输出提供支持。它们在Java输入输出类库中的对应物就是PipedWriter类(允许任务向管道写)和PipedReader类(允许不同任务从一个管道中读取)。这个模型可以看成是“生产者-消费者”问题的变体,这里的管道就是一个封装好的解决方案。
```java
class Sender implements Runnable {
private Random random = new Random(47);
private PipedWriter writer = new PipedWriter();
public PipedWriter getWriter() {
return writer;
}
@Override
public void run() {
try {
while (true) {
for (char c = 'A'; c <= 'z'; c++) {
writer.write(c);
TimeUnit.MILLISECONDS.sleep(random.nextInt(500));
}
}
} catch (InterruptedException e) {
System.out.println("writer got InterruptedException !");
} catch (IOException e) {
System.out.println("writer got IOException !");
}
}
}
class Receiver implements Runnable {
private PipedReader reader;
public Receiver(Sender sender) throws IOException {
reader = new PipedReader(sender.getWriter());
}
@Override
public void run() {
try {
while (true) {
// blocks until characters are there:
System.out.println("Read: " + (char)reader.read() + ".");
}
} catch (IOException e) {
System.out.println("Receiver got IOException !");
}
}
}
public class PipedIO {
public static void main(String[] args) throws IOException, InterruptedException {
Sender sender = new Sender();
Receiver receiver = new Receiver(sender);
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(sender);
executorService.execute(receiver);
TimeUnit.SECONDS.sleep(10);
executorService.shutdownNow();
}
}
```
某个任务在等待另一个任务,而后者有等待别的任务,这样一直下去,直到这个链条上的任务有在等待第一个任务释放锁。这得到了一个任务之间相互等待的连续循环,没有哪个线程能继续。这被称之为死锁。
它被用来同步一个或者多个任务,强制他们等待由其他任务执行的一组操作完成。
```java
class TaskPortion implements Runnable {
private static int counter = 0;
private final int id = counter++;
private static Random random = new Random(47);
private final CountDownLatch latch;
public TaskPortion(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try {
doWork();
latch.countDown();
} catch (InterruptedException e) {
// Accepted this way to exit
}
}
public void doWork() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(random.nextInt(2000));
System.out.println(this + "completed");
}
@Override
public String toString() {
return String.format("%1$-3d", id);
}
}
//Waits on the CountDownLatch
class WaitingTask implements Runnable {
private static int counter = 0;
private final int id = counter++;
private final CountDownLatch latch;
public WaitingTask(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try {
latch.wait();
System.out.println("Latch barrier passed for " + this);
} catch (InterruptedException e) {
System.out.println(this + "interrupted! ");
}
}
@Override
public String toString() {
return String.format("WaitingTsk %1$-3d ", id);
}
}
public class CountDownLatchDemo {
static final int SIZE = 100;
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
// All must share a single CountDownLatch object:
CountDownLatch latch = new CountDownLatch(SIZE);
for (int i = 0; i < 10; i++) {
executorService.execute(new WaitingTask(latch));
}
for (int i = 0; i < SIZE; i++) {
executorService.execute(new TaskPortion(latch));
}
System.out.println("Launched all tasks");
executorService.shutdown();
}
}
```
- TaskPortion将随机休眠一段时间,以模仿这部分工作完成[portion:部分],而WaitingTask表示系统中必须等待的部分,他要等待到问题的初始部分完成为止。所有任务都使用了在main()中定义的同一个单一的CountDownLatch。
其适用于这种场景:你希望创建一组任务,他们并行地执行任务,然后在进行下一个步骤之前等待,直至所有任务都完成(看起来有些像join())。它使得所有的并行任务都将在栅栏处列队,因此可以一致地向前移动。
class Horse implements Runnable {
private static int counter = 0;
private final int id = counter++;
private int strides = 0;
private static Random random = new Random(47);
private static CyclicBarrier cyclicBarrier;
public Horse(CyclicBarrier c) {
cyclicBarrier = c;
}
public synchronized int getStrides() {
return strides;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (this) {
strides += random.nextInt(3);
}
cyclicBarrier.await();
}
} catch (InterruptedException e) {
// A legitimate way to exit
} catch (BrokenBarrierException e) {
// This one we want to know about
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return "Horse{" +
"id=" + id +
" ";
}
public String tracks() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < getStrides(); i++) {
builder.append("*");
}
builder.append(id);
return builder.toString();
}
}
public class HorseRace {
static final int FINISH_LINE = 75;
private List horseList = new ArrayList<>();
private ExecutorService executorService = Executors.newCachedThreadPool();
private CyclicBarrier cyclicBarrier;
public HorseRace(int nHorses,final int pause) {
cyclicBarrier = new CyclicBarrier(nHorses, new Runnable() {
@Override
public void run() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < FINISH_LINE; i++) {
builder.append("=");
}
System.out.println(builder);
for (Horse horse:
horseList) {
System.out.println(horse.tracks());
}
for (Horse horse:
horseList) {
if (horse.getStrides() >= FINISH_LINE) {
System.out.println(horse + "won!");
executorService.shutdownNow();
return;
}
try {
TimeUnit.MILLISECONDS.sleep(pause);
} catch (InterruptedException e) {
System.out.println("barrier-action sleep interrupted");
}
}
}
});
for (int i = 0; i < nHorses; i++) {
Horse horse = new Horse(cyclicBarrier);
horseList.add(horse);
executorService.execute(horse);
}
}
public static void main(String[] args) {
int nHorse = 7;
int pause = 200;
if (args.length > 0) {
int n = new Integer(args[0]);
nHorse = n > 0 ? n :nHorse;
}
if (args.length > 1) {
int p = new Integer(args[1]);
pause = p > -1 ? p:pause;
}
new HorseRace(nHorse,pause);
}
}
class DelayedTask implements Runnable, Delayed {
private static int counter = 0;
private final int id = counter++;
private final int delta;
private final long trigger;
protected static List sequence =
new ArrayList<>();
public DelayedTask(int delayInMilliseconds) {
delta = delayInMilliseconds;
trigger = System.nanoTime() + NANOSECONDS.convert(delta,MILLISECONDS);
sequence.add(this);//这种用法需要注意!!
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(
trigger - System.nanoTime(),NANOSECONDS
);
}
@Override
public int compareTo(Delayed o) {
DelayedTask that = (DelayedTask)o;
if (trigger < that.trigger) return -1;
if (trigger > that.trigger) return 1;
return 0;
}
@Override
public void run() {
System.out.println(this + " ");
}
@Override
public String toString() {
return String.format("[%1$-4d]",delta) + " Task " + id;
}
public String summary() {
return "(" + id
+ ":" +delta + ")";
}
public static class EndSentinel extends DelayedTask {
private ExecutorService executorService;
public EndSentinel(int delay,ExecutorService executorService){
super(delay);
this.executorService = executorService;
}
public void run() {
for (DelayedTask task:
sequence) {
System.out.println(task.summary() + " ");
}
System.out.println();
System.out.println(this + "Calling shutdownNow()");
executorService.shutdownNow();
}
}
}
class DelayTaskConsumer implements Runnable {
private DelayQueue taskDelayQueue;
public DelayTaskConsumer(DelayQueue taskDelayQueue) {
this.taskDelayQueue = taskDelayQueue;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
taskDelayQueue.take().run();//Run task with th current thread
}
} catch (InterruptedException e) {
// Acceptable way t exit
}
System.out.println("Finished DelayedTaskConsumer");
}
}
public class DelayQueueDemo {
public static void main(String[] args) {
Random random = new Random(47);
ExecutorService executorService = Executors.newCachedThreadPool();
DelayQueue taskDelayQueue = new DelayQueue<>();
// Fill with tasks that have random delays;
for (int i = 0; i <20; i++) {
taskDelayQueue.put(new DelayedTask(random.nextInt(5000)));
}
// Set the stopping point
taskDelayQueue.add(new DelayedTask.EndSentinel(5000,executorService));
executorService.execute(new DelayTaskConsumer(taskDelayQueue));
}
}
class PrioritizedTask implements Runnable,Comparable {
private Random random = new Random(47);
private static int counter = 0;
private final int id = counter++;
private final int priority;
protected static List sequence =
new ArrayList<>();
public PrioritizedTask(int priority) {
this.priority = priority;
sequence.add(this);
}
@Override
public int compareTo(PrioritizedTask o) {
return priority < o.priority ? 1 :
(priority > o.priority ? -1 : 0);
}
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(random.nextInt(250));
} catch (InterruptedException e) {
// Acceptable way to exit;
}
System.out.println(this);
}
@Override
public String toString() {
return String.format("[%1$-3d]",priority) + " Task " +id;
}
public String summary() {
return "(" + id + ":" + priority + ")";
}
public static class EndSentinel extends PrioritizedTask {
private ExecutorService executorService;
public EndSentinel(ExecutorService executorService) {
super(-1);
this.executorService = executorService;
}
public void run() {
int count = 0;
for (PrioritizedTask prioritizedTask:
sequence) {
if (++count % 5 == 0) {
System.out.println();
}
}
System.out.println();
System.out.println(this + " Calling shutdownNow()");
executorService.shutdownNow();
}
}
}
class PrioritizedTaskProducer implements Runnable {
private Random random = new Random(47);
private Queue queue;
private ExecutorService executorService;
public PrioritizedTaskProducer(Queue queue, ExecutorService executorService) {
this.queue = queue;
this.executorService = executorService;//Used for EndSentinel
}
@Override
public void run() {
// Unbounded queue; never blocks
// FIll it up fast with random priorities;
for (int i = 0; i <20; i++) {
queue.add(new PrioritizedTask(random.nextInt(10)));
Thread.yield();
}
// Trickle in highest-priority jobs;
try {
for (int i = 0; i < 10; i++) {
TimeUnit.MILLISECONDS.sleep(250);
queue.add(new PrioritizedTask(10));
}
// Add jobs,lowest priority first;
for (int i = 0; i < 10; i++) {
TimeUnit.MILLISECONDS.sleep(250);
}
// A sentinel to stop all the tasks
queue.add(new PrioritizedTask.EndSentinel(executorService));
} catch (InterruptedException e) {
// Acceptable way to exit;
}
System.out.println("Finished PrioritizedTaskProducer");
}
}
class PrioritizedTaskConsumer implements Runnable {
private PriorityBlockingQueue queue;
public PrioritizedTaskConsumer(PriorityBlockingQueue queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
// Use current thread to run the task;
queue.take().run();
}
} catch (InterruptedException e) {
// Acceptable way to exit;
}
System.out.println("Finished PrioritizedTaskConsumer");
}
}
public class PriorityBlockingQueueDemo {
public static void main(String[] args) {
Random random = new Random(47);
ExecutorService executorService = Executors.newCachedThreadPool();
PriorityBlockingQueue queue =
new PriorityBlockingQueue<>();
executorService.execute(new PrioritizedTaskProducer(queue,executorService));
executorService.execute(new PrioritizedTaskConsumer(queue));
}
}
public class GreenhouseScheduler {
private volatile boolean light = false;
private volatile boolean water = false;
private String thermostat = "Day";
public synchronized String getThermostat() {
return thermostat;
}
public synchronized void setThermostat(String value) {
thermostat = value;
}
ScheduledThreadPoolExecutor executor =
new ScheduledThreadPoolExecutor(10);
public void schedule(Runnable event, long delay) {
executor.schedule(event,delay, TimeUnit.MILLISECONDS);
}
public void
repeat(Runnable event, long initialDelay, long period) {
executor.scheduleAtFixedRate(event,initialDelay,period,TimeUnit.MILLISECONDS);
}
class LightOn implements Runnable {
@Override
public void run() {
// put hardware control code here to
// physically turn on the light
System.out.println("Turning on lights");
light = true;
}
}
class LightOff implements Runnable {
@Override
public void run() {
System.out.println("Turning off lights");
light = false;
}
}
class WaterOn implements Runnable {
@Override
public void run() {
System.out.println("Turning greenhouse water on");
water = true;
}
}
class WaterOff implements Runnable {
@Override
public void run() {
System.out.println("Turning greenhouse water off");
water = false;
}
}
class ThermostatNight implements Runnable {
@Override
public void run() {
System.out.println("Thermostat to night setting");
setThermostat("Night");
}
}
class ThermostatDay implements Runnable {
@Override
public void run() {
System.out.println("Thermostat to day setting");
setThermostat("Day");
}
}
class Bell implements Runnable {
@Override
public void run() {
System.out.println("Bing!");
}
}
class Terminate implements Runnable {
@Override
public void run() {
System.out.println("Terminating");
executor.shutdownNow();
// Must start a separate task to do this job;
// since the scheduler has been shut down;
new Thread() {
public void run() {
for (DataPoint dataPoint:
data) {
System.out.println(dataPoint);
}
}
}.start();
}
}
// New feature: data collection
static class DataPoint {
final Calendar time;
final float temperature;
final float humidity;
public DataPoint(Calendar calendar, float temp, float hum) {
time = calendar;
temperature = temp;
humidity = hum;
}
public String toString() {
return time.getTime() +
String.format(
" temperature: %1$.1f humidity: %2$.2f",
temperature,humidity);
}
}
private Calendar lastTime = Calendar.getInstance();
{//Adjust date t the half hour
lastTime.set(Calendar.MINUTE,30);
lastTime.set(Calendar.SECOND,00);
}
private float lastTemp = 65.0f;
private int tempDirection = +1;
private float lastHumidity = 50.0f;
private int humidityDirection = +1;
private Random random = new Random(47);
List data = Collections.synchronizedList(new ArrayList());
class CollectData implements Runnable {
@Override
public void run() {
System.out.println("Collecting data");
synchronized (GreenhouseScheduler.this) {
// Pretend the interval is longer than it is;
lastTime.set(Calendar.MINUTE,lastTime.get(Calendar.MINUTE) + 30);
// One in 5 chances of reversing the direction;
if (random.nextInt(5) == 4) {
tempDirection = -tempDirection;
}
// Store previous value
lastTemp = lastTemp +
tempDirection * random.nextFloat();
if (random.nextInt() == 4) {
humidityDirection = -humidityDirection;
}
lastHumidity = lastHumidity + humidityDirection * random.nextFloat();
// Calendar must be cloned, otherwise all
// DataPoints hold references to the same lastTime
// For a basic object like Calendar, clone() is OK
data.add(new DataPoint((Calendar)lastTime.clone(),
lastTemp, lastHumidity));
}
}
}
public static void main(String[] args) {
GreenhouseScheduler greenhouseScheduler = new GreenhouseScheduler();
greenhouseScheduler.schedule(greenhouseScheduler.new Terminate(),5000);
// Former "Restart" class not necessary
greenhouseScheduler.repeat(greenhouseScheduler.new Bell(),0,1000);
greenhouseScheduler.repeat(greenhouseScheduler.new ThermostatNight(),0,2000);
greenhouseScheduler.repeat(greenhouseScheduler.new LightOn(),0,200);
greenhouseScheduler.repeat(greenhouseScheduler.new LightOff(),0,400);
greenhouseScheduler.repeat(greenhouseScheduler.new WaterOn(),0,600);
greenhouseScheduler.repeat(greenhouseScheduler.new WaterOff(),0,800);
greenhouseScheduler.repeat(greenhouseScheduler.new ThermostatDay(),0,1400);
greenhouseScheduler.repeat(greenhouseScheduler.new CollectData(),500,500);
}
}
计数信号量
允许n个任务同时访问这个资源。对象池
的概念,他管理者数量有限的对象,当要使用对象时可以签出他们,而在用户使用完毕后,再将它们签回。这种功能可以被封装到一个泛型类中。
public class Pool<T> {
private int size;
private List items = new ArrayList<>();
private volatile boolean[] checkedOut;
private Semaphore available;
public Pool(Class classObject, int size) {
this.size = size;
checkedOut = new boolean[size];
available = new Semaphore(size,true);
// Load pool with objects that can be checked out;
for (int i = 0; i < size; i++) {
try {
// Assumes a default constructor
items.add(classObject.newInstance());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public T checkOut() throws InterruptedException {
available.acquire();//如果没有可用的,available将会在这儿阻塞
return getItem();
}
public void checkIn(T x) {
if (releaseItem(x)) {
available.release();
}
}
public synchronized T getItem() {
for (int i = 0; i < size; i++) {
if (!checkedOut[i]) {
checkedOut[i] = true;
return items.get(i);
}
}
return null;
}
private synchronized boolean releaseItem(T item) {
int index = items.indexOf(item);
if (index == -1) return false;// Not in the list
if (checkedOut[index]) {
checkedOut[index] = false;
return true;
}
return false;
}
}
public class Fat {
private volatile double d;
private static int counter = 0;
private final int id = counter++;
public Fat() {
for (int i = 1; i < 10000; i++) {
d += (Math.PI + Math.E) / (double)i;
}
}
public void operation() {
System.out.println(this);
}
@Override
public String toString() {
return "Fat{" +
"d=" + d +
", id=" + id +
'}';
}
}
class CheckoutTask implements Runnable {
private static int counter = 0;
private final int id = counter++;
private Pool pool;
public CheckoutTask(Pool pool) {
this.pool = pool;
}
@Override
public void run() {
try {
T item = pool.checkOut();
System.out.println(this + "checking out " + item);
TimeUnit.SECONDS.sleep(1);
System.out.println(this + "checking in " + item);
pool.checkIn(item);
} catch (InterruptedException e) {
// Acceptable way to terminate
}
}
@Override
public String toString() {
return "CheckoutTask{" +
"id=" + id +
", pool=" + pool +
'}';
}
}
public class SemaphoreDemo {
final static int SIZE = 25;
public static void main(String[] args) throws Exception {
final Pool pool =
new Pool<>(Fat.class,SIZE);
ExecutorService executorService =
Executors.newCachedThreadPool();
for (int i = 0; i < SIZE; i++) {
executorService.execute(new CheckoutTask<>(pool));
}
System.out.println("All CheckoutTasks created");
List fatList = new ArrayList<>();
for (int i = 0; i < SIZE; i++) {
Fat fat = pool.checkOut();
System.out.println(i + ": main() thread checked out ");
fat.operation();
fatList.add(fat);
}
Future> blocked = executorService.submit(new Runnable() {
@Override
public void run() {
try {
// Semaphore prevents additional checkout
// so call is blocked
pool.checkOut();
} catch (InterruptedException e) {
System.out.println("checkOut() Interrupted");
}
}
});
TimeUnit.SECONDS.sleep(2);
blocked.cancel(true);
System.out.println("Checking in objects in " + fatList);
for (Fat f :
fatList) {
pool.checkIn(f);
}
for (Fat f :
fatList) {
pool.checkIn(f);
}
executorService.shutdown();
}
}
semaphore.acquire(),获取信号量,没信号量可用时,将进行阻塞
semaphore.release(); 释放信号量
class ExchangerProducer implements Runnable {
private Surrogate.Generator generator;
private Exchanger> exchanger;
private List holder;
public ExchangerProducer(Surrogate.Generator generator, Exchanger> exchanger, List holder) {
this.generator = generator;
this.exchanger = exchanger;
this.holder = holder;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
for (int i = 0; i < ExchangerDemo.size; i++) {
holder.add(generator.next());
// Exchange full for empty
holder = exchanger.exchange(holder);
}
}
} catch (InterruptedException e) {
// OK to terminate this way
}
}
}
class ExchangerConsumer implements Runnable {
private Exchanger> exchanger;
private List holder;
private volatile T value;
public ExchangerConsumer(Exchanger> exchanger, List holder) {
this.exchanger = exchanger;
this.holder = holder;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
holder = exchanger.exchange(holder);
for (T x:
holder) {
value = x;
holder.remove(x);
}
}
} catch (InterruptedException e) {
// OK to terminate this way;
}
System.out.println("Final value: " + value);
}
}
public class ExchangerDemo {
static int size = 10;
static int delay = 5;
public static void main(String[] args) throws InterruptedException {
if (args.length > 0) {
size = new Integer(args[0]);
}
if (args.length > 1) {
delay = new Integer(args[1]);
}
ExecutorService executorService = Executors.newCachedThreadPool();
Exchanger> exchanger = new Exchanger<>();
List
producerList = new CopyOnWriteArrayList<>(),
consumerList = new CopyOnWriteArrayList<>();
executorService.execute(new ExchangerProducer(exchanger,BasicGenerator.create(Fat.class),producerList));
executorService.execute(new ExchangerConsumer(exchanger,consumerList));
TimeUnit.SECONDS.sleep(delay);
executorService.shutdownNow();
}
}
Exchanger类中的exchange(String x) 方法具有阻塞的特点,也就是说此方法被调用后等待其他线程来获取数据,如果没有其他线程取得数据,则就会一直阻塞等待下去。
Exchanger类中的exchange(String x, long timeout, TimeUnit unit)查看官方API可知这个方法的作用是在制定的时间内没有其他线程获取数据,则会抛出异常
Java SE5特别添加了新的容器,通过使用更灵巧的技术来消除加锁,从而提高线程安全的性能。
这些免锁容器背后的通用策略是:对容器的修改可以与读取操作同时发生,只要读取者只能看到完成修改的结果即可。修改是在容器数据结构的某个部分的一个单独的副本(有时是整个数据结构的副本)上执行的,并且这个副本在修改过程中是不可视的。只有当修改完成后,被修改的结构才会自动地与主数据结构进行交换,之后读取者就可以看到这个修改了。
- 在CopyOnWriteArrayList中,写入将导致创建整个底层数组的副本,而源数组将保留在原地,使得复制的数组在被修改时,读取操作可以安全地执行。CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
- Java并发编程:并发容器之CopyOnWriteArrayList(转载)
- CopyOnWriteArraySet将使用CopyOnWriteArrayList来实现其免锁行为。
- ConcurrentHashMap和ConcurrentLinkedQueue使用了类似的技术,允许并发的读取和写入,但是容器中只有部分内容而不是整个容器可以被复制和修改。然而,任何修改在完成之前,读取者仍旧不能看到它们。And ConcurrentHashMap不会抛出ConcurrentModificationException异常。
只要你主要是从免锁容器中读取,那么它就会比其synchronized对应物快许多,因为获取和释放锁的开销被省掉了。如果需要向免锁容器中执行少量写入,那么情况仍旧如此,但是什么算“少量”,这是一个很有意思的问题。
public abstract class Tester<C> {
static int testReps = 10;
static int testCycles = 1000;
static int containerSize = 1000;
abstract C containerInitializer();
abstract void startReadersAndWriters();
C testContainer;
String testId;
int nReaders;
int nWriters;
volatile long readResult = 0;
volatile long readTime = 0;
volatile long writeTime = 0;
CountDownLatch endLatch;
static ExecutorService executorService =
Executors.newCachedThreadPool();
Integer[] writeData;
Tester(String testId, int nReaders, int nWriters) {
this.testId = testId + " " +
nReaders + "r " + nWriters + "w";
this.nReaders = nReaders;
this.nWriters = nWriters;
writeData = Generated.array(Integer.class, new RandomGenerator.Integer(),containerSize);
for (int i = 0; i < testReps; i++) {
runTest();
readTime = 0;
writeTime = 0;
}
}
void runTest() {
endLatch = new CountDownLatch(nReaders + nWriters);
testContainer = containerInitializer();
startReadersAndWriters();
try {
endLatch.await();
} catch (InterruptedException e) {
System.out.println("endLatch interrupted");
}
System.out.printf("%-27s %14d\n","readTime + writeTime =",readTime + writeTime);
}
abstract class TestTask implements Runnable {
abstract void test();
abstract void putResults();
long duration;
public void run() {
long startTime = System.nanoTime();
test();
duration = System.nanoTime() - startTime;
synchronized (Tester.this) {
putResults();
}
endLatch.countDown();
}
}
public static void main(String[] args) {
if (args.length > 0) {
testReps = new Integer(args[0]);
}
if (args.length > 1) {
testCycles = new Integer(args[1]);
}
if (args.length > 2) {
containerSize = new Integer(args[2]);
}
System.out.printf("%-27s %14s %14s\n",
"Type", "Read time", "Write time");
}
}
abstract class ListTest extends Tester> {
ListTest(String testId, int nReaders, int nWriters) {
super(testId, nReaders, nWriters);
}
class Reader extends TestTask {
long result = 0;
void test() {
for (long i = 0; i for (int index = 0; index < containerSize; index++) {
result += testContainer.get(index);
}
}
}
void putResults() {
readResult += result;
readTime += duration;
}
}
class Writer extends TestTask {
void test() {
for (long i =0; i < testCycles; i++) {
for (int index = 0; index < containerSize; index++) {
testContainer.set(index,writeData[index]);
}
}
}
void putResults() {
writeTime +=duration;
}
}
@Override
void startReadersAndWriters() {
for (int i = 0; i < nReaders; i++) {
executorService.execute(new Reader());
}
for (int i = 0; i < nWriters; i++) {
executorService.execute(new Writer());
}
}
}
class SynchronizedArrayListTest extends ListTest {
List containerInitializer() {
return Collections.synchronizedList(
new ArrayList(
new CountingIntegerList(containerSize)
)
);
}
SynchronizedArrayListTest(int nReaders, int nWriters) {
super("Synched ArrayList",nReaders,nWriters);
}
}
class CopyOnWriterArrayListTest extends ListTest {
List containerInitializer() {
return new CopyOnWriteArrayList(
new CountingIntegerList(containerSize)
);
}
CopyOnWriterArrayListTest(int nReaders,int nWriters) {
super("Synched ArrayList",nReaders,nWriters);
}
}
public class ListComparisons {
public static void main(String[] args) {
Tester.initMain(args);
new SynchronizedArrayListTest(10,0);
new SynchronizedArrayListTest(9,1);
new SynchronizedArrayListTest(5,5);
new CopyOnWriterArrayListTest(10,0);
new CopyOnWriterArrayListTest(9,1);
new CopyOnWriterArrayListTest(5,5);
Tester.executorService.shutdown();
}
}
public class FastSimulation {
static final int N_ELEMENTS = 100000;
static final int N_GENS = 30;
static final int N_EVOLVERS = 50;
static final AtomicInteger[][] GRID =
new AtomicInteger[N_ELEMENTS][N_GENS];
static Random random = new Random(47);
static class Evoler implements Runnable {
@Override
public void run() {
while (!Thread.interrupted()) {
// Randomly select an element to work on
int element = random.nextInt(N_ELEMENTS);
for (int i = 0; i < N_GENS; i++) {
int previous = element - 1;
if (previous < 0) previous = N_ELEMENTS - 1;
int next = element + 1;
if (next >= N_ELEMENTS) next = 0;
int oldValue = GRID[element][i].get();
// Perform some kind of modeling calculation
int newValue = oldValue +
GRID[previous][i].get() + GRID[next][i].get();
newValue /= 3; // Average the three values
if (!GRID[element][i].compareAndSet(oldValue,newValue)) {
/***
* Policy here to deal with failure. Here, we
* just report it and ignore it; our model
* will eventually deal with it,
*/
System.out.println("OldValue changed from " + oldValue);
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < N_ELEMENTS; i++) {
for (int j = 0; j < N_GENS; j++) {
GRID[i][j] = new AtomicInteger(random.nextInt(1000));
}
}
for (int i = 0; i < N_EVOLVERS; i ++) {
executorService.execute(new Evoler());
}
TimeUnit.SECONDS.sleep(5);
executorService.shutdownNow();
}
}
public class ReaderWriterList<T> {
private ArrayList lockedList;
// Make the ordering fair;
private ReentrantReadWriteLock lock =
new ReentrantReadWriteLock(true);
public ReaderWriterList(int size, T initialValue) {
lockedList = new ArrayList(
Collections.nCopies(size,initialValue)
);
}
public T set(int index, T element) {
Lock wLock = lock.writeLock();
wLock.lock();
try {
return lockedList.set(index,element);
} finally {
wLock.unlock();
}
}
public T get(int index) {
Lock rLock = lock.readLock();
rLock.lock();
try {
// Show that multiple readers
// may acquire the read lock
if (lock.getReadHoldCount() > 1) {
System.out.println(lock.getReadHoldCount());
}
return lockedList.get(index);
} finally {
rLock.unlock();
}
}
public static void main(String[] args) throws Exception {
new ReaderWriterListTest(30,1);
}
}
class ReaderWriterListTest {
ExecutorService executorService =
Executors.newCachedThreadPool();
private final static int SIZE = 100;
private static Random random = new Random(47);
private ReaderWriterList list =
new ReaderWriterList<>(SIZE,0);
private class Writer implements Runnable {
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
list.set(i , random.nextInt());
TimeUnit.MILLISECONDS.sleep(100);
}
} catch (InterruptedException e) {
// Acceptable way to exit
}
System.out.println("Writer finished, shutting down");
executorService.shutdownNow();
}
}
private class Reader implements Runnable {
@Override
public void run() {
try {
while (!Thread.interrupted()) {
for (int i = 0; i < SIZE; i++) {
list.get(i);
TimeUnit.MILLISECONDS.sleep(1);
}
}
} catch (InterruptedException e) {
// Acceptable way to exit
}
}
}
public ReaderWriterListTest(int readers, int writers) {
for (int i = 0; i new Reader());
}
for (int i = 0; i new Writer());
}
}
}
活动对象
或行动者
,之所以称这些对象为“活动的”,是因为每个对象都维护着他自己的工作器线程和消息队列,并且所有对这种对象的请求都将进入队列排队,实现了任何时刻都只能运行其中一个。public class ActiveObjectDemo {
private ExecutorService executorService =
Executors.newSingleThreadExecutor();
private Random random =
new Random(47);
// Insert a random delay to produce the effect
// of a calculation time
private void pause(int factor) {
try {
TimeUnit.MILLISECONDS.sleep(
100 + random.nextInt()
);
} catch (InterruptedException e) {
System.out.println("sleep() interrupted");
}
}
public Future
calculateInt(final int x, final int y) {
return executorService.submit(new Callable() {
@Override
public Integer call() throws Exception {
System.out.println("starting " + x + " + " + y);
pause(500);
return x + y;
}
});
}
public Future
calculateFloat(final float x, final float y) {
return executorService.submit(new Callable() {
@Override
public Float call() throws Exception {
System.out.println("starting " + x + " + " + y);
return x + y;
}
});
}
public void shutdown() {
executorService.shutdown();
}
public static void main(String[] args) {
ActiveObjectDemo demo = new ActiveObjectDemo();
// Prevents ConcurrentModificationException
List> results =
new CopyOnWriteArrayList>();
for (float f= 0.0f; f < 1.0f; f += 0.2f) {
results.add(demo.calculateFloat(f,f));
}
for (int i = 0; i < 5; i++) {
results.add(demo.calculateInt(i,i));
}
System.out.println("All asynch calls made");
while (results.size() > 0) {
for (Future> future:
results) {
if (future.isDone()) {
try {
System.out.println(future.get());
} catch (Exception e) {
throw new RuntimeException(e);
}
results.remove(future);
}
}
}
demo.shutdown();
}
}
消息
,而每个活动对象方法的返回值都是一个具有泛型参数的Future,而这个泛型参数就是该方法中实际的返回类型。通过这种方式,方法调用几乎可以立即返回,调用者可以使用Future来发现何时任务完成,并收集实际的返回值。