Java多线程与并发库高级应用-工具类介绍

java.util.concurrent.Lock

1、Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,
锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。

  lock替代synchronized

  

复制代码
class Outputer {
Lock lock
= new ReentrantLock(); public void output(String name) {
int len = name.length();

lock.lock();
try{
for (int i = 0; i < len; i++) {
char c = name.charAt(i);
System.out.print(c);
}
}
finally{
lock.unlock();
//这里防止内部代码出现异常,即无论如何最后都会释放锁
}
lock.unlock();
System.out.println();
}
}
复制代码

 

售票系统

复制代码
package com.java.juc;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

public static void main(String[] args) {

Ticket ticket
= new Ticket();

new Thread(ticket, "窗口1售票").start();

new Thread(ticket, "窗口2售票").start();

new Thread(ticket, "窗口3售票").start();


}

}

class Ticket implements Runnable {

private int ticket = 100;

private Lock lock = new ReentrantLock();

@Override
public void run() {

while (true) {

lock.lock();

try {

if (ticket > 0) {

Thread.sleep(
20);

System.out.println(Thread.currentThread().getName()

+ ",余票量:" + ticket--);

}

}
catch (InterruptedException e) {

e.printStackTrace();

}
finally {

lock.unlock();

}

}

}

}

复制代码

 

 

 

2、读写锁:

读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。
* 如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;
* 如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。
* 总之,读的时候上读锁,写的时候上写锁!

复制代码
/* 面试题:3个线程读,3个线程写 同一个数据
 */
public class ReadWriteLockTest {
public static void main(String[] args) {
final Queue3 queue = new Queue3();

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

new Thread(new Runnable() {

@Override

public void run() {

while(true){

queue.get();

}

}

}).start();

new Thread(new Runnable() {

@Override

public void run() {

queue.set(
new Random().nextInt(10000));

}

}).start();

}

}

}

class Queue3{

private Object data = null; //共享数据 ,只能有一个线程写该数据,但可以有多个线程同时读
ReadWriteLock rwl = new ReentrantReadWriteLock(); //读写锁

public void get(){

try {

rwl.readLock().lock();
//上读锁 可以有多个线程同时读

System.out.println(Thread.currentThread().getName() + " be ready to read data!");

Thread.sleep((
long)Math.random() * 1000);

System.out.println(Thread.currentThread().getName()
+ " have read data : "+ data);

}
catch (InterruptedException e) {

}
finally{

rwl.readLock().unlock();
//释放读锁

}

}

public void set(Object data){

try {

rwl.writeLock().lock();
//添加写锁,保证只能有一个线程进行写操作

System.out.println(Thread.currentThread().getName() + " be read to write data: "+ data);

Thread.sleep((
long)Math.random() * 1000);

this.data = data;

System.out.println(Thread.currentThread().getName()
+ "has write data");

}
catch (InterruptedException e) {

e.printStackTrace();

}
finally{

rwl.writeLock().unlock();
//释放写锁

}

}

}

复制代码

 简单的读写锁示例

复制代码
package com.java.juc;

import java.util.Random;

import java.util.concurrent.locks.ReadWriteLock;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class TestReadWriteLock {

public static void main(String[] args) {

final ReadWriteLockDemo demo = new ReadWriteLockDemo();

new Thread(new Runnable(){

@Override
public void run() {

demo.set(
new Random().nextInt(5000));

}

},
"Write").start();

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

new Thread(new Runnable() {

@Override

public void run() {

demo.get();

}

},
"Read").start();

}

}

}

class ReadWriteLockDemo{

private int number = 0;

private ReadWriteLock lock = new ReentrantReadWriteLock();

public void get(){

try{

lock.readLock().lock();

System.out.println(Thread.currentThread().getName()
+" "+number);

}
finally{

lock.readLock().unlock();

}

}

public void set(int number){

try{

lock.writeLock().lock();

this.number = number;

}
finally{

lock.writeLock().unlock();

}

}

}

复制代码

 

 

 Hibernate的一个面试题:

  User user = session.load(id,User.class);

  User user = session.get(id,User.class);

  以上两个的却别。

  get()方式,直接查询数据库,如果查询到赋值给User对象,如果没有查询到则返回为null

  load()方式,实际上是从User的一个代理中获取, User$Proxy中包含有一个真实的User对象,当调用load()时,如果成员变量User为null,则从数据库查询将记录返回并给User赋值,当load()时User不为null,则直接返回User对象

 

复制代码
/**
* 面试题: 设计一个缓存系统 *
@author Administrator
*
*/
public class CacheDemo {

Map<String, Object> cache = new HashMap<String, Object>();

public static void main(String[] args) {

}

private ReadWriteLock rwl = new ReentrantReadWriteLock();

public Object getData(String key){

rwl.readLock().lock();

Object value
= null;

try {

value
= cache.get(key);

if(value == null){

rwl.readLock().unlock();

rwl.writeLock().lock();

try {

if(value == null){ //防止后边线程加载数据,使用双端检测机制

value
= "xxx"; //queryDB

cache.put(key, value);

}

}
finally{

rwl.writeLock().unlock();
}

rwl.readLock().lock();

}

}
catch (Exception e) {

}
finally{

rwl.readLock().unlock();

}

return value;

}

}

复制代码

 

 

ReadWriteLock javaAPI中有缓存的代码:

class CachedData {
Object data;
volatile boolean cacheValid;
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

void processCachedData() {

rwl.readLock().lock();

if (!cacheValid) {

// Must release read lock before acquiring write lock

rwl.readLock().unlock();

rwl.writeLock().lock();

// Recheck state because another thread might have acquired

// write lock and changed state before we did.

if (!cacheValid) {

data = ...

cacheValid = true;

}

// Downgrade by acquiring read lock before releasing write lock

rwl.readLock().lock();

rwl.writeLock().unlock(); // Unlock write, still hold read

}

use(data);

rwl.readLock().unlock();

}

}

 

3、Condition 实现线程通信

传统的线程通信方式

复制代码
/*
 * 传统线程通信
 * 主线程和子线程分别打印 100次 和 10次,循环50次
 */
public class TraditionalThreadCommunication2 {

public static void main(String[] args) {

final Buiness buiness = new Buiness();

new Thread(new Runnable() {

@Override

public void run() {

for(int i = 1;i<=50;i++){

buiness.sub(i);

}

}

}).start();

for(int i = 1;i<=50;i++){

buiness.main(i);

}

}

static class Buiness{

private boolean isShouldSub = false; //主线程先打印

public synchronized void main(int j){ //进行同步,防止在打印时被其他线程干扰

while(isShouldSub){ //这里使用while 防止假唤醒

try {

this.wait(); //wait() 和 notify() 必须出现在synchronized同步中

} catch (InterruptedException e) {

e.printStackTrace();

}

}

for(int i = 1;i<=100;i++){

System.out.println(
"main thread print "+ i + " loop of " + j);

}

isShouldSub
= true;

this.notify();

}

public synchronized void sub(int j){

while(!isShouldSub){

try {

this.wait();

}
catch (InterruptedException e) {

e.printStackTrace();

}

}

for(int i = 1 ; i<=10;i++){

System.out.println(
"sub thread print "+ i + " loop of " + j);

}

isShouldSub
= false;

this.notify();

}

}

}

复制代码

 

 

将上述程序改写为使用Condition

复制代码
/*
* 传统线程通信
* 主线程和子线程分别打印 100次 和 10次,循环50次
* 改写成使用 Condition 的方式
*/
public class TraditionalThreadCommunication2 {

public static void main(String[] args) {

final Buiness buiness = new Buiness();

new Thread(new Runnable() {

@Override

public void run() {

for(int i = 1;i<=50;i++){

buiness.sub(i);

}

}

}).start();

for(int i = 1;i<=50;i++){

buiness.main(i);

}

}

/**

* 将程序改写为使用Lock&Condition的方式进行 同步和通信

*
@author Administrator



/


static class Buiness{
Lock lock
= new ReentrantLock();

Condition condition
= lock.newCondition();

private boolean isShouldSub = false; //主线程先打印
public void main(int j){ //进行同步,防止在打印时被其他线程干扰
lock.lock();

try {

while(isShouldSub){ //这里使用while 防止假唤醒

try {

condition.await();

// this.wait(); //wait() 和 notify() 必须出现在同步监视器内部中

} catch (Exception e) {

e.printStackTrace();

}

}

for(int i = 1;i<=100;i++){

System.out.println(
"main thread print "+ i + " loop of " + j);

}

isShouldSub
= true;

condition.signal();

// this.notify();

} finally {

lock.unlock();

}

}

public void sub(int j){

lock.lock();

try {

while(!isShouldSub){

try {

condition.await();

// this.wait();

} catch (Exception e) {

e.printStackTrace();

}

}

for(int i = 1 ; i<=10;i++){

System.out.println(
"sub thread print "+ i + " loop of " + j);

}

isShouldSub
= false;

condition.signal();

// this.notify();

} finally{

lock.unlock();

}

}

}

}

复制代码

main thread print 1 loop of 1
main thread print 2 loop of 1
main thread print 3 loop of 1
main thread print 4 loop of 1
main thread print 5 loop of 1
main thread print 6 loop of 1
main thread print 7 loop of 1
...
main thread print 99 loop of 1
main thread print 100 loop of 1
sub thread print 1 loop of 1
sub thread print 2 loop of 1
sub thread print 3 loop of 1
sub thread print 4 loop of 1
sub thread print 5 loop of 1
sub thread print 6 loop of 1
sub thread print 7 loop of 1
sub thread print 8 loop of 1
sub thread print 9 loop of 1
sub thread print 10 loop of 1
main thread print 1 loop of 2
main thread print 2 loop of 2
main thread print 3 loop of 2
main thread print 4 loop of 2
main thread print 5 loop of 2
main thread print 6 loop of 2
main thread print 7 loop of 2
main thread print 8 loop of 2
main thread print 9 loop of 2
...
main thread print 99 loop of 2
main thread print 100 loop of 2
sub thread print 1 loop of 2
sub thread print 2 loop of 2
sub thread print 3 loop of 2
sub thread print 4 loop of 2
sub thread print 5 loop of 2
sub thread print 6 loop of 2
sub thread print 7 loop of 2
sub thread print 8 loop of 2
sub thread print 9 loop of 2
sub thread print 10 loop of 2
main thread print 1 loop of 3
main thread print 2 loop of 3
main thread print 3 loop of 3

...

 

使用Condition比传统的好处

可以实现多路Condition ,在javaAPI中有

class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();

final Object[] items = new Object[100];

int putptr, takeptr, count;

public void put(Object x) throws InterruptedException {

lock.lock();

try {

while (count == items.length)

notFull.await();

items[putptr] = x;

if (++putptr == items.length) putptr = 0;

++count;

notEmpty.signal();

} finally {

lock.unlock();

}

}

public Object take() throws InterruptedException {

lock.lock();

try {

while (count == 0)

notEmpty.await();

Object x = items[takeptr];

if (++takeptr == items.length) takeptr = 0;

--count;

notFull.signal();

return x;

} finally {

lock.unlock();

}

}

}

使用多路Condition,可以扩展上述的一个例子,老大打印完 -> 老二   老二-> 老三  老三-> 老大  老大-> 老二...

 

复制代码
/**
* 第一个线程循环100次,第二个线程循环10次,第三个线程循环20次,如此循环50次,请写出程序 这里使用Condition
*
*
@author Administrator
*
*/
public class ThreeConditionCommunication {

public static void main(String[] args) {

final Business2 business = new Business2();

new Thread(new Runnable() {

@Override

public void run() {

for (int i = 1; i <= 50; i++) {

business.sub2(i);

}

}

}).start();

new Thread(new Runnable() {

@Override

public void run() {

for (int i = 1; i <= 50; i++) {

business.sub3(i);

}

}

}).start();

for (int i = 1; i <= 50; i++) {

business.main(i);

}

}

}

class Business2 {

Lock lock
= new ReentrantLock();

Condition condition1
= lock.newCondition();

Condition condition2
= lock.newCondition();

Condition condition3
= lock.newCondition();

private int shoudeSub = 1;

public void sub2(int i) {

lock.lock();

try {

while (shoudeSub != 2) { // 这里也可以用 if ,用while比较好一些 As in the one argument

// version, interrupts and spurious wakeups are

// possible, and this method should always be

// used in a loop

try { // 防止线程有可能被假唤醒 (while放在这里提现了水准)

condition2.await(); //等待

} catch (InterruptedException e) {

e.printStackTrace();

}

}

for (int j = 1; j <= 100; j++) {

System.out.println(
"sub2 thread sequence of " + j + ", loop of " + i);

}

shoudeSub
= 3;

condition3.signal();
//唤醒

} finally{

lock.unlock();

}

}

public void sub3(int i) {

lock.lock();

try {

while (shoudeSub != 3) { // 这里也可以用 if ,用while比较好一些 As in the one argument

// version, interrupts and spurious wakeups are

// possible, and this method should always be

// used in a loop

try { // 防止线程有可能被假唤醒 (while放在这里提现了水准)

condition3.await(); //等待

} catch (InterruptedException e) {

e.printStackTrace();

}

}

for (int j = 1; j <= 20; j++) {

System.out.println(
"sub3 thread sequence of " + j + ", loop of " + i);

}

shoudeSub
= 1;

condition1.signal();
//唤醒

} finally{

lock.unlock();

}

}

public void main(int i) {

lock.lock();

try {

while (shoudeSub != 1) {

try {

condition1.await();

}
catch (InterruptedException e) {

e.printStackTrace();

}

}

for (int j = 1; j <= 10; j++) {

System.out.println(
"main thread sequence of " + j + ", loop of "

+ i);

}

shoudeSub
= 2;

condition2.signal();

}
finally{

lock.unlock();

}

}

/**

*

* synchronized (obj) { 这里的obj与obj.wait必须相同,否则会抛异常 while (<condition does

* not hold>) obj.wait(); ... // Perform action appropriate to condition }

*/

}

复制代码

 

Condition的一个例子:

 编写一个程序,开启3个线程 ,这三个线程的ID分别为 A,B, C,每个线程将自己的ID 在屏幕上打印10遍,要求输出的结果必须按顺序显示。

如:ABCABCABC.....依次递归

这里实现了一个比题目稍微难得例子,A 打印10次,B打印20次 ,C打印5次依次递归20次。

复制代码
package com.java.juc;

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class TestAlternative {

public static void main(String[] args) {

final Alternative alternative = new Alternative();

new Thread(new Runnable(){

@Override

public void run() {

for(int i = 1;i<=20;i++){

alternative.loopA(i);

}

}

},
"A").start();

new Thread(new Runnable(){

@Override

public void run() {

for(int i = 1;i<=20;i++){

alternative.loopB(i);

}

}

},
"B").start();

new Thread(new Runnable(){

@Override

public void run() {

for(int i = 1;i<=20;i++){

alternative.loopC(i);

System.out.println(
"-----------------");

}

}

},
"C").start();



}



}



class Alternative{

private int number = 1;

private Lock lock = new ReentrantLock();

private Condition condition1 = lock.newCondition();

private Condition condition2 = lock.newCondition();

private Condition condition3 = lock.newCondition();

void loopA(int outerLoop){

lock.lock();

try{

while(number != 1){

condition1.await();

}

for(int i = 1;i<=10;i++){

System.out.println(Thread.currentThread().getName()
+ "\t" + i + "\t" + outerLoop);

}

number
= 2;

condition2.signal();

}
catch(Exception e){

}
finally {

lock.unlock();

}

}

void loopB(int outerLoop){

lock.lock();

try{

while(number != 2){

condition2.await();

}

for(int i = 1;i<=20;i++){

System.out.println(Thread.currentThread().getName()
+ "\t" + i + "\t" + outerLoop);

}

number
= 3;

condition3.signal();

}
catch(Exception e){



}
finally{

lock.unlock();

}

}

void loopC(int outerLoop){

lock.lock();

try{

while(number != 3){

condition3.await();

}

for(int i = 1;i<=5;i++){

System.out.println(Thread.currentThread().getName()
+ "\t" + i + "\t" + outerLoop);

}

number
= 1;

condition1.signal();

}
catch(Exception e){



}
finally{

lock.unlock();

}

}

}

复制代码

 

 

java5的Semaphere同步工具

  Semaphore实现信号灯

  Semaphore可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。

  假设一个文件同时可以被3个人访问,来了5个人,同时只有3个访问。3个中任何一个出来后,等待的就可以进去了。

复制代码
public class SemaphoreTest {

public static void main(String[] args) {


ExecutorService service
= Executors.newCachedThreadPool();

final Semaphore sp = new Semaphore(3); //还有一个构造方法,Semaphore(int permits, boolean fair) fair参数为true表示谁先来谁先进,一种公平的原则

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

Runnable runnable
= new Runnable(){

public void run(){

try {

sp.acquire();

}
catch (InterruptedException e1) {

e1.printStackTrace();

}

System.out.println(
"线程" + Thread.currentThread().getName() +

"进入,当前已有" + (3-sp.availablePermits()) + "个并发");

try {

Thread.sleep((
long)(Math.random()*10000));

}
catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(
"线程" + Thread.currentThread().getName() +

"即将离开");

sp.release();
//下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元

System.out.println("线程" + Thread.currentThread().getName() +
"已离开,当前已有" + (3-sp.availablePermits()) + "个并发");

}

};

service.execute(runnable);

}

}

}

复制代码

 

 

单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了 "锁",再由另外一个线程释放"锁",这可应用于死锁恢复的一些场合。

 

java5 的CyclicBarrier同步工具

复制代码
/**
* 表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面,
* 这就好比整个公司的人员利用周末时间集体郊游一样,先各自从家出发到公司集合后,
* 再同时出发到公园游玩,在指定地点集合后再同时开始就餐,…。
*
@author Administrator
*
*/
public class CyclicBarrierTest {

public static void main(String[] args) {

ExecutorService threadPool
= Executors.newCachedThreadPool();

final CyclicBarrier cb = new CyclicBarrier(3);

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

Runnable runnable
= new Runnable() {

public void run() {

try {

Thread.sleep((
long) (Math.random() * 10000));

System.out.println(
"线程"+ Thread.currentThread().getName()

+ "即将到达集合点1,当前已有 "+(cb.getNumberWaiting()+1) +"个已经到达,"+(cb.getNumberWaiting() == 2?"都到齐了,继续走啊":"正在等待"));

cb.await();

Thread.sleep((long) (Math.random() * 10000));

System.out.println(
"线程"+ Thread.currentThread().getName()

+ "即将到达集合点2,当前已有 "+(cb.getNumberWaiting()+1) +"个已经到达,"+(cb.getNumberWaiting() == 2?"都到齐了,继续走啊":"正在等待"));

cb.await();

Thread.sleep((long) (Math.random() * 10000));

System.out.println(
"线程"+ Thread.currentThread().getName()

+ "即将到达集合点3,当前已有 "+(cb.getNumberWaiting()+1) +"个已经到达,"+(cb.getNumberWaiting() == 2?"都到齐了,继续走啊":"正在等待"));

cb.await();

}
catch (Exception e) {

// TODO: handle exception

}

}

};

threadPool.execute(runnable);

}

threadPool.shutdown();

}



}

复制代码

 

 

 

java5的CountDownLatch同步工具

  CountDownLatch : 闭锁,在完成某些运算时,只有其他所有线程的运算全部完成,当前运算才继续执行

  CountDownLatch应用1:比如要统计5个线程并发的运行时间,即线程的开始时间与最后一个线程的运行结束时间的间隔时间。

  

复制代码
package com.java.juc;

import java.util.concurrent.CountDownLatch;

public class TestCountDownLatch2 {

public static void main(String[] args) {

CountDownLatch latch = new CountDownLatch(5);

LatchDemo2 ld
= new LatchDemo2(latch);

long start = System.currentTimeMillis();

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

new Thread(ld).start();


}
try {

latch.await();
//先执行完成的线程需要等待还没有执行完的线程

} catch (InterruptedException e) {

e.printStackTrace();

}

long end = System.currentTimeMillis();

System.out.println(
"cost: "+ (end - start));

}



}

class LatchDemo2 implements Runnable{

private CountDownLatch latch;

public LatchDemo2(CountDownLatch latch) {

this.latch = latch;

}

@Override

public void run() {



try {

synchronized(this){

for(int i = 0;i<50000;i++){ //找出50000以内的所有偶数

if(i % 2 == 0){

System.out.println(i);

}

}

}

}
finally{

latch.countDown();
//为了让这一句一定执行可以放在finally中

}

}

}

复制代码

 

 

 

  还可以应用于计算所有种类商品的平均销售总和,平均销售时间等,如果使用单线程计算效率非常低,相当于是串行计算。可以使用并行计算,按照商品种类进行区分并行的计算。可以将最终的每个线程的计算结果在进行汇总,可以得出最终的的总的销售数据,这就可以使用CountDownLatch进行操作,可以大幅度提高效率。(京东)

 

应用:运动员跑步比赛,得到最终的排名需要在所有运动员都完成之后,公布最终的结果。

复制代码
/**
 * 犹如倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减一,
* 当计数器到达0时,则所有等待者或单个等待者开始执行。
* 可以实现一个人(也可以是多个人)等待其他所有人都来通知他,可以实现一个人通知多个人的效果,
* 类似裁判一声口令,运动员同时开始奔跑,或者所有运动员都跑到
* 终点后裁判才可以公布结果。还可以实现一个计划需要多个领导都签字后
* 才能继续向下实施的情况
*
@author Administrator

*
*/
public class CountDownLetchTest {

public static void main(String[] args) {

ExecutorService executorService
= Executors.newCachedThreadPool();

final CountDownLatch cdOrder = new CountDownLatch(1); //计数器初始值 1

final CountDownLatch cdAnswer = new CountDownLatch(3);

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

Runnable runnable
= new Runnable() {

@Override
public void run() {

try {

System.out.println(
"线程"+Thread.currentThread().getName()

+"正准备接受命令");

cdOrder.await();

System.out.println(
"线程"+Thread.currentThread().getName()

+"已接受命令");

Thread.sleep((
long)(Math.random()10000));

System.out.println(
"线程"+Thread.currentThread().getName()

+"回应命令处理结果");

cdAnswer.countDown();

}
catch (Exception e) {

// TODO: handle exception

}

}

};

executorService.execute(runnable);

}

try {

Thread.sleep((
long)(Math.random()
10000));

System.out.println(
"线程"+Thread.currentThread().getName()

+"即将发布命令");

cdOrder.countDown();
//计数器数值减 1

System.out.println("线程"+Thread.currentThread().getName()

+"已发送命令,正在等待结果");

cdAnswer.await();

System.out.println(
"线程"+Thread.currentThread().getName()

+"已收到所有响应结果");

}
catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

executorService.shutdown();

}

}

复制代码

 java 中CycliBarriar 和 CountDownLatch 有什么区别?

  这两个的区别是CyclicBarrier 可以重复使用已经通过的障碍,而 CountdownLatch 不能重复使用。

 

 

java5的Exchanger同步工具

复制代码
/**
* 用于实现两个人之间的数据交换,每个人在完成一定的事物后想与对方交换数据,第一个先拿出数据的人将
* 一直等待第二个人拿着数据到来时,才能彼此交换数据。
*
@author Administrator
*
*/
public class ExchangerTest {

public static void main(String[] args) {

ExecutorService executorService
= Executors.newCachedThreadPool();

final Exchanger exchanger = new Exchanger();

executorService.execute(
new Runnable() {

@Override

public void run() {

try {

String data1
= "aaa";

System.out.println(
"线程" + Thread.currentThread().getName()

+ "正在把数据" + data1 + "换出去");

Thread.sleep((
long) (Math.random() * 10000));

String data2
= (String) exchanger.exchange(data1);

System.out.println(
"线程" + Thread.currentThread().getName()

+ "换回的数据为 " + data2);

}
catch (Exception e) {

// TODO: handle exception

}

}

});

executorService.execute(
new Runnable() {

@Override

public void run() {

try {

String data1
= "bbb";

System.out.println(
"线程" + Thread.currentThread().getName()

+ "正在把数据" + data1 + "换出去");

Thread.sleep((
long) (Math.random() * 10000));

String data2
= (String) exchanger.exchange(data1);

System.out.println(
"线程" + Thread.currentThread().getName()

+ "换回的数据为 " + data2);

}
catch (Exception e) {

// TODO: handle exception

}

}

});

}

}

复制代码

 

打印结果为:

线程 pool-1-thread-1正把数据 aaa 换出去

线程 pool-1-thread-2正把数据 bbb 换出去

线程 pool-1-thread-2换回的数据为 aaa

线程 pool-1-thread-1换回的数据为 bbb

 

 

 

 

 

 

posted @ 2018-06-07 17:36  星朝  阅读(341)  评论(0)    收藏  举报