一、CyclicBarrier
介绍
CyclicBarrier也叫同步屏障,允许一组线程全部等待彼此达到共同屏障点的同步辅助。循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。 屏障被称为循环,因为它可以在等待的线程被释放之后重新使用。
举个比较常见的例子,就比如运动员比赛赛跑,他要先等所有运动员就位,然后裁判才会发令。这就是一种循环栅栏
的概念!
源码
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
在CyclicBarrier中最重要的方法莫过于await()方法,每个线程调用await方法告诉CyclicBarrier已经到达屏障位置,线程被阻塞。源码如下:
BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
案例
package com.fair.concurrency.juc3;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CyclicBarrier;
public class Demo1CyclicBarrier
{
public static void main(String[] args)
{
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
List<Thread> threadList = new ArrayList<>();
for (int i = 1; i < 6; i++)
{
Thread t = new Thread(new Athlete(cyclicBarrier, "运动员" + i));
threadList.add(t);
}
for (Thread t : threadList)
{
t.start();
}
}
static class Athlete implements Runnable
{
private CyclicBarrier cyclicBarrier;
private String name;
public Athlete(CyclicBarrier cyclicBarrier, String name)
{
this.cyclicBarrier = cyclicBarrier;
this.name = name;
}
@Override
public void run()
{
System.out.println(name + "就位");
try
{
cyclicBarrier.await();
System.out.println(name + "到达终点。");
} catch (Exception e)
{
}
}
}
}
二、CountDownLatch
介绍
CountDownLatch是一个计数的闭锁(也有个说法叫发令枪闭锁
),作用与CyclicBarrier有点儿相似!
用给定的计数 初始化CountDownLatch。由于调用了countDown() 方法,所
以在当前计数到达零之前,await方法会一直受阻塞。之后,会释放所有等待
的线程,await 的所有后续调用都将立即返回。
这种现象只出现一次,计数无法被重置。如果需要重置计数,请考虑使用
CyclicBarrier。
区别:
- CountDownLatch:一个或者多个线程,等待其他多个线程完成某件事情之后
才能执行; - CyclicBarrier:多个线程互相等待,直到到达同一个同步点,再继续一起执行。
案例
package com.fair.concurrency.juc3;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class Demo2CountDownLatch
{
public static void main(String[] args)
{
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
List<Thread> threadList = new ArrayList<>();
for (int i = 0; i < 5; i++)
{
CountDownLatch countDownLatch = new CountDownLatch(1);
//起点运动员
Thread t1 = new Thread(new Athlete(cyclicBarrier, countDownLatch, "起点运动员" + i));
//接力运动员
Thread t2 = new Thread(new Athlete(countDownLatch, "接力运动员" + i));
threadList.add(t1);
threadList.add(t2);
}
for (Thread t : threadList)
{
t.start();
}
}
static class Athlete implements Runnable
{
private CyclicBarrier cyclicBarrier;
private String name;
private CountDownLatch countDownLatch;
//起点运动员
public Athlete(CyclicBarrier cyclicBarrier, CountDownLatch countDownLatch, String name)
{
this.cyclicBarrier = cyclicBarrier;
this.countDownLatch = countDownLatch;
this.name = name;
}
//接力运动员
public Athlete(CountDownLatch countDownLatch, String name)
{
this.countDownLatch = countDownLatch;
this.name = name;
}
@Override
public void run()
{
//判断是否是起点运动员
if (cyclicBarrier != null)
{
System.out.println(name + "就位");
try
{
cyclicBarrier.await();
System.out.println(name + "到达交接点。");
//已经到达交接点
countDownLatch.countDown();
} catch (Exception e)
{
}
}
//判断是否是接力运动员
if (cyclicBarrier == null)
{
System.out.println(name + "就位");
try
{
countDownLatch.await();
System.out.println(name + "到达终点。");
} catch (Exception e)
{
}
}
}
}
}
三、Semaphore
介绍
Semaphore是一个控制访问多个共享资源的计数器,和CountDownLatch一样,其本质上是一个
共享锁
。Semaphore维护了一个信号量许可集。线程可以获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以释放它所持有的信号量许可,被释放的许可归还到许可集中,可以被其他线程再次获取。
举个例子:
假设停车场仅有5个停车位,一开始停车场没有车辆所有车位全部空着,然后先后到来三辆车,停车场车位够,安排进去停车,然后又来三辆,这个时候由于只剩两个停车位,所有只能停两辆,其余一辆必须在外面候着,直到停车场有空车位,当然以后每来一辆都需要在外面等着。当停车场有车开出去,里面有空位了,则安排一辆车进去(至于是哪辆车 要看选择的机制是公平还是非公平)。
案例
package com.fair.concurrency.juc3;
import java.util.concurrent.Semaphore;
public class Demo3Semaphore
{
public static void main(String[] args)
{
Parking parking = new Parking(3);
for (int i = 0; i < 5; i++)
{
new Car(parking).start();
}
}
static class Parking
{
//信号量
private Semaphore semaphore;
public Parking(int count)
{
semaphore = new Semaphore(count);
}
public void park()
{
try
{
//获取信号量
semaphore.acquire();
long time = (long) (Math.random() * 10);
System.out.println(Thread.currentThread().getName() + "进入停车场,停车" + time + "秒...");
Thread.sleep(time);
System.out.println(Thread.currentThread().getName() + "开出停车场...");
} catch (InterruptedException e)
{
e.printStackTrace();
} finally
{
//释放信号量
semaphore.release();
}
}
}
static class Car extends Thread
{
private final Parking parking;
public Car(Parking parking)
{
this.parking = parking;
}
@Override
public void run()
{
//进入停车场
parking.park();
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/16370.html