您的位置:首页 > 编程语言 > Java开发

JAVA线程14 - 新特性:同步工具

2014-03-05 16:23 309 查看

一、Semaphore

1. 简介

Semaphore实现信号量。

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

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

2. 示例

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreTest {

public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
final Semaphore sp = new Semaphore(3);
for (int i = 0; i < 10; i++) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
sp.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"进入,当前已有并发"+(3-sp.availablePermits()));
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"即将离开");
sp.release();
System.out.println("线程"+Thread.currentThread().getName()+"已离开,当前已有并发"+(3-sp.availablePermits()));
}
};
es.execute(r);
}
es.shutdown();
}
}

二、CyclicBarrier

1. 简介

障碍器。表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面。

2. 示例

import java.util.Date;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicBarrierTest {

public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
final CyclicBarrier cb = new CyclicBarrier(5);
for (int i = 0; i < 5; i++) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(10000));
System.out.println(new Date()+":线程"+Thread.currentThread().getName()+"到达目的地1,当前已到达"+(cb.getNumberWaiting()+1)+",正在等候");
cb.await();
System.out.println(new Date()+":所有线程已到达,向目的地2出发");

Thread.sleep(new Random().nextInt(10000));
System.out.println(new Date()+":线程"+Thread.currentThread().getName()+"到达目的地2,当前已到达"+(cb.getNumberWaiting()+1)+",正在等候");
cb.await();
System.out.println(new Date()+":所有线程已到达,向目的地3出发");

Thread.sleep(new Random().nextInt(10000));
System.out.println(new Date()+":线程"+Thread.currentThread().getName()+"到达目的地3,当前已到达"+(cb.getNumberWaiting()+1)+",正在等候");
cb.await();
System.out.println(new Date()+":所有线程已到达,任务结束");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
};
es.execute(r);
}
es.shutdown();
}

}

三、CountDownLatch

1. 简介

犹如倒计时计数器,调用CountDownLatch对象的countDown()方法就将计数器-1,当计数器到达0时,则所有等待者或者单个等待着开始执行。

2. 示例

import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchTest {

public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);
final CountDownLatch cdAnswer = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
//Thread.sleep(new Random().nextInt(10000));
System.out.println(new Date()+":线程"+Thread.currentThread().getName()+"准备接受命令");
cdOrder.await();
System.out.println(new Date()+":线程"+Thread.currentThread().getName()+"已接受命令");
Thread.sleep(new Random().nextInt(10000));
System.out.println(new Date()+":线程"+Thread.currentThread().getName()+"处理命令");
cdAnswer.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
es.execute(r);
}

try {
Thread.sleep(new Random().nextInt(10000));
System.out.println(new Date()+":线程"+Thread.currentThread().getName()+"即将发布命令");
cdOrder.countDown();
System.out.println(new Date()+":线程"+Thread.currentThread().getName()+"已发布命令,正等待结果");
cdAnswer.await();
System.out.println(new Date()+":线程"+Thread.currentThread().getName()+"已收到所有响应结果");
} catch (Exception e) {
e.printStackTrace();
}

es.shutdown();
}
}

四、Exchanger

1. 简介

Exchanger用于两个线程之间的数据交换。每个线程在完成一定任务后想与对方交换数据,第一个先拿出数据的线程将一直等待第二个线程拿着数据的到来,才能彼此交换数据。

2. 示例

import java.util.Date;
import java.util.Random;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* Exchanger交换机 两个线程之间用户交换数据
*/
public class ExchangerTest {

public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
// 线程之间交换数据
final Exchanger exchanger = new Exchanger();

service.execute(new Runnable() {
public void run() {
try {
String data = "【数据1】";
System.out.println(new Date()+":"+Thread.currentThread().getName() + "准备把" + data + "换出去");
Thread.sleep(new Random().nextInt(10000));

String data2 = (String) exchanger.exchange(data);
System.out.println(new Date()+":"+Thread.currentThread().getName() + "换回的数据是" + data2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

service.execute(new Runnable() {
public void run() {
try {
String data = "【数据2】";
System.out.println(new Date()+":"+Thread.currentThread().getName() + "准备把" + data + "换出去");
Thread.sleep(new Random().nextInt(10000));

String data2 = (String) exchanger.exchange(data);
System.out.println(new Date()+":"+Thread.currentThread().getName() + "换回的数据是" + data2);
} catch (Exception e) {
e.printStackTrace();
}
}
});

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: