JAVA并发编程-障碍器CyclicBarrier,计数器CountDownLatch,信号量Semaphore
2016-10-07 20:36
746 查看
CountDownLatch利用它可以实现类似计数器的功能。
比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了构造器
两个子线程模拟任务,执行后
主线程等待
通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。
我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了构造器:
参数barrierAction当这些线程都达到barrier状态时会执行的内容。最重要await()方法:
当四个线程都到达barrier状态后,会从四个线程中选择一个线程去执行Runnable。
[b]等待了指定的时间发现第四个线程还没有达到barrier,就抛出异常并继续执行后面的任务[/b]
构造器:
[b]4个方法都会被阻塞[/b]
立即得到执行结果[/b]
2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。
比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了构造器
public
CountDownLatch(
int
count) {};
//参数count为计数值方法
public
void
await()
throws
InterruptedException {};
//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public
boolean
await(
long
timeout, TimeUnitunit)
throws
InterruptedException {};
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public
void
countDown() {};
//将count值减1例子:
public
class
Test {
public
static
void
main(String[] args){
final
CountDownLatch latch=
new
CountDownLatch(
2
);
/**
两个子线程模拟任务,执行后
latch.countDown();
***/
new
Thread(){
public
void
run() {
try
{
System.out.println(
"子线程"
+Thread.currentThread().getName()+
"正在执行"
);
Thread.sleep(
3000
);
System.out.println(
"子线程"
+Thread.currentThread().getName()+
"执行完毕"
);
latch.countDown();
}
catch
(InterruptedException e){
e.printStackTrace();
}
};
}.start();
new
Thread(){
public
void
run() {
try
{
System.out.println(
"子线程"
+Thread.currentThread().getName()+
"正在执行"
);
Thread.sleep(
3000
);
System.out.println(
"子线程"
+Thread.currentThread().getName()+
"执行完毕"
);
latch.countDown();
}
catch
(InterruptedException e){
e.printStackTrace();
}
};
}.start();
/**
主线程等待
latch.await();当latch为0的时候执行下面任务
**/
try
{
System.out.println(
"等待2个子线程执行完毕..."
);
latch.await();
System.out.println(
"2个子线程已经执行完毕"
);
System.out.println(
"继续执行主线程"
);
}
catch
(InterruptedException e){
e.printStackTrace();
}
}
}[b]CyclicBarrier[/b]
通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。
我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了构造器:
public
CyclicBarrier(
int
parties,
RunnablebarrierAction){
}
public
CyclicBarrier(
int
parties) {
}参数parties指让多少个线程或者任务等待至barrier状态;
参数barrierAction当这些线程都达到barrier状态时会执行的内容。最重要await()方法:
public
int
await()
throws
InterruptedException,
BrokenBarrierException{};
public
int
await(
long
timeout,
TimeUnitunit)
throws
InterruptedException,BrokenBarrierException,TimeoutException例子1:[b]假若有若干个线程都要进行写数据操作,并且只有所有线程都完成写数据操作之后,这些线程才能继续做后面的事情[/b]
{};
public
class
Test {
public
static
void
main(String[]
args){
int
N
=
4
;
CyclicBarrier
barrier=
new
CyclicBarrier(N);
for
(
int
i=
0
;i<N;i++)
new
Writer(barrier).start();
}
static
class
Writer
extends
Thread{
private
CyclicBarrier cyclicBarrier;
public
Writer(CyclicBarrier
cyclicBarrier){
this
.cyclicBarrier
=cyclicBarrier;
}
@Override
public
void
run() {
System.out.println(
"线程"
+Thread.currentThread().getName()+
"正在写入数据..."
);
try
{
Thread.sleep(
5000
);
//以睡眠来模拟写入数据操作
System.out.println(
"线程"
+Thread.currentThread().getName()+
"写入数据完毕,等待其他线程写入完毕"
);
cyclicBarrier.await();
}
catch
(InterruptedException e){
e.printStackTrace();
}
catch
(BrokenBarrierException e){
e.printStackTrace();
}
System.out.println(
"所有线程写入完毕,继续处理其他任务..."
);
}
}
}例子2:[b]在所有线程写入操作完之后,进行额外的其他操作可以为CyclicBarrier提供Runnable参数:[/b]
当四个线程都到达barrier状态后,会从四个线程中选择一个线程去执行Runnable。
public
class
Test {
public
static
void
main(String[]
args){
int
N
=
4
;
CyclicBarrier
barrier=
new
CyclicBarrier(N,
new
Runnable() {
@Override
public
void
run() {
System.out.println(
"当前线程"
+Thread.currentThread().getName());
}
});
for
(
int
i=
0
;i<N;i++)
new
Writer(barrier).start();
}
static
class
Writer
extends
Thread{
private
CyclicBarrier cyclicBarrier;
public
Writer(CyclicBarrier
cyclicBarrier){
this
.cyclicBarrier
=cyclicBarrier;
}
@Override
public
void
run() {
System.out.println(
"线程"
+Thread.currentThread().getName()+
"正在写入数据..."
);
try
{
Thread.sleep(
5000
);
//以睡眠来模拟写入数据操作
System.out.println(
"线程"
+Thread.currentThread().getName()+
"写入数据完毕,等待其他线程写入完毕"
);
cyclicBarrier.await();
}
catch
(InterruptedException e){
e.printStackTrace();
}
catch
(BrokenBarrierException e){
e.printStackTrace();
}
System.out.println(
"所有线程写入完毕,继续处理其他任务..."
);
}
}
}例子3:await()
[b]等待了指定的时间发现第四个线程还没有达到barrier,就抛出异常并继续执行后面的任务[/b]
public
class
Test {
public
static
void
main(String[]
args){
int
N
=
4
;
CyclicBarrier
barrier=
new
CyclicBarrier(N);
for
(
int
i=
0
;i<N;i++) {
if
(i<N-
1
)
new
Writer(barrier).start();
else
{
try
{
Thread.sleep(
5000
);
}
catch
(InterruptedException e){
e.printStackTrace();
}
new
Writer(barrier).start();
}
}
}
static
class
Writer
extends
Thread{
private
CyclicBarrier cyclicBarrier;
public
Writer(CyclicBarrier
cyclicBarrier){
this
.cyclicBarrier
=cyclicBarrier;
}
@Override
public
void
run() {
System.out.println(
"线程"
+Thread.currentThread().getName()+
"正在写入数据..."
);
try
{
Thread.sleep(
5000
);
//以睡眠来模拟写入数据操作
System.out.println(
"线程"
+Thread.currentThread().getName()+
"写入数据完毕,等待其他线程写入完毕"
);
try
{
cyclicBarrier.await(
2000
, TimeUnit.MILLISECONDS);
}
catch
(TimeoutException
e){
//
TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
catch
(InterruptedException e){
e.printStackTrace();
}
catch
(BrokenBarrierException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"所有线程写入完毕,继续处理其他任务..."
);
}
}
}例子4:[b]CyclicBarrier是可以重用的[/b]
public
class
Test {
public
static
void
main(String[]
args){
int
N
=
4
;
CyclicBarrier
barrier=
new
CyclicBarrier(N);
for
(
int
i=
0
;i<N;i++) {
new
Writer(barrier).start();
}
try
{
Thread.sleep(
25000
);
}
catch
(InterruptedException e){
e.printStackTrace();
}
System.out.println(
"CyclicBarrier重用"
);
for
(
int
i=
0
;i<N;i++) {
new
Writer(barrier).start();
}
}
static
class
Writer
extends
Thread{
private
CyclicBarrier cyclicBarrier;
public
Writer(CyclicBarrier
cyclicBarrier){
this
.cyclicBarrier
=cyclicBarrier;
}
@Override
public
void
run() {
System.out.println(
"线程"
+Thread.currentThread().getName()+
"正在写入数据..."
);
try
{
Thread.sleep(
5000
);
//以睡眠来模拟写入数据操作
System.out.println(
"线程"
+Thread.currentThread().getName()+
"写入数据完毕,等待其他线程写入完毕"
);
cyclicBarrier.await();
}
catch
(InterruptedException e){
e.printStackTrace();
}
catch
(BrokenBarrierException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"所有线程写入完毕,继续处理其他任务..."
);
}
}
}Semaphore
构造器:
public
Semaphore(
int
permits)
{
//参数permits表示许可数目,即同时可以允许多少线程进行访问
sync
=
new
NonfairSync(permits);
}
public
Semaphore(
int
permits,
boolean
fair)
{
//这个多了一个参数fair表示是否是公平的,即等待时间越久的越先获取许可
sync
=(fair)?
new
FairSync(permits)
:
new
NonfairSync(permits);
}
[b]4个方法都会被阻塞[/b]
public
void
acquire()
throws
InterruptedException
{}
//获取一个许可
public
void
acquire(
int
permits)
throws
InterruptedException
{}
//获取permits个许可
public
void
release()
{}
//释放一个许可
public
void
release(
int
permits)
{}
//释放permits个许可acquire()用来获取一个许可,若无许可能够获得,则会一直等待,直到获得许可。release()用来释放许可。注意,在释放许可之前,必须先获获得许可。[b]4个方法
立即得到执行结果[/b]
public
boolean
tryAcquire()
{};
//尝试获取一个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public
boolean
tryAcquire(
long
timeout, TimeUnitunit)
throws
InterruptedException {};
//尝试获取一个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false
public
boolean
tryAcquire(
int
permits)
{};
//尝试获取permits个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public
boolean
tryAcquire(
int
permits,
long
timeout, TimeUnitunit)
throws
InterruptedException
{};
//尝试获取permits个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false[b]availablePermits()方法得到可用的许可数目[/b]例子:[b]假若一个工厂有5台机器,但是有8个工人,一台机器同时只能被一个工人使用,只有使用完了,其他工人才能继续使用[/b]
public
class
Test {
public
static
void
main(String[]
args){
int
N
=
8
;
//工人数
Semaphore
semaphore=
new
Semaphore(
5
);
//机器数目
for
(
int
i=
0
;i<N;i++)
new
Worker(i,semaphore).start();
}
static
class
Worker
extends
Thread{
private
int
num;
private
Semaphore semaphore;
public
Worker(
int
num,Semaphore semaphore){
this
.num
=num;
this
.semaphore
=semaphore;
}
@Override
public
void
run() {
try
{
semaphore.acquire();
System.out.println(
"工人"
+
this
.num+
"占用一个机器在生产..."
);
Thread.sleep(
2000
);
System.out.println(
"工人"
+
this
.num+
"释放出机器"
);
semaphore.release();
}
catch
(InterruptedException e){
e.printStackTrace();
}
}
}
}总结:1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同: CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行; 而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行; 另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。
2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。
相关文章推荐
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程深入学习——CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore(转)
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程之2——同步工具类的使用(CountDownLatch,CyclicBarrier,BlockungQueue,Semaphore)
- 《Java 7 并发编程指南》学习概要 (3)Semaphore, CountDownLatch, CyclicBarrier , Phaser, Exchanger
- 使用Java辅助类(CountDownLatch、CyclicBarrier、Semaphore)并发编程
- Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- 14、Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- [置顶] java 并发编程实战书籍学习 第五章,CountDownLatch,FutureTask,CyclicBarrier,Semaphore学习
- java并发编程:CountDownLatch、CyclicBarrier和Semaphore