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

JAVA并发编程-障碍器CyclicBarrier,计数器CountDownLatch,信号量Semaphore

2016-10-07 20:36 746 查看
CountDownLatch利用它可以实现类似计数器的功能。
比如有一个任务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其实和锁有点类似,它一般用于控制对某组资源的访问权限。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: