Java的并发包中有各种并发类,今天通过这个例子来熟悉使用CyclicBarrier类。
CyclicBarrier类就像一个起跑线,定义了赛道的大小,当所有运动员(多线程)同时在起跑线,
那么CyclicBarrier就会触发起跑动作。
以下是Java使用CyclicBarrier模拟运动比赛的例子
新建一个gradle工程,目录结构如下
在build.gradle中引入spring和lombok两个架包
plugins {
id 'java'
}
group 'com.drama'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
maven {
url 'http://179.179.179.46:8087/repository/maven-public/'
}
}
dependencies {
compile("org.springframework:spring-context:4.1.6.RELEASE")
compile("org.projectlombok:lombok:1.18.8")
testCompile group: 'junit', name: 'junit', version: '4.12'
}
定义配置类MyConfig,定义线程池的大小,这里定为6
package demo.cyclicbarrier;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
@ComponentScan("demo.cyclicbarrier")
@EnableAsync
public class MyConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(6); //这里的CorePoolSize一定要大于6(1个干扰者,5个运动员)
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
定义运动比赛类型和顺序
package demo.cyclicbarrier;
import lombok.Getter;
public enum SportEnum {
Swim("游泳"),Run("跑步"),Cycle("骑车");
@Getter
private final String sportName;
SportEnum(String sportName) {
this.sportName = sportName;
}
public SportEnum nextSport(){
if(this == Swim)
return Run;
else if(this == Run)
return Cycle;
else
return Swim;
}
}
定义MySignal,用CyclicBarrier表示起跑线,用SportEnum表示比赛状态
package demo.cyclicbarrier;
import lombok.Getter;
import lombok.Synchronized;
import java.util.concurrent.CyclicBarrier;
public class MySignal {
@Getter
private final CyclicBarrier startLine;
@Getter
private SportEnum sport;
private String winner;
public MySignal(int size) {
this.startLine = new CyclicBarrier(size,new StartLine(this));
sport = SportEnum.Swim;
}
@Synchronized
public void nextSport(){
sport = sport.nextSport();
}
@Synchronized
public boolean setWinner(String winner){
if(this.winner==null){
this.winner = winner;
return true;
}
return false;
}
}
class StartLine implements Runnable{
private final MySignal mySignal;
StartLine(MySignal mySignal) {
this.mySignal = mySignal;
}
@Override
public void run() {
System.out.println(mySignal.getSport().getSportName()+" 比赛开始");
mySignal.nextSport();
}
}
定义运动员的动作和干扰者的动作,通过@Async来启动多线程
package demo.cyclicbarrier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.Set;
import java.util.concurrent.BrokenBarrierException;
@Service
public class TaskService {
@Async
public void troublemaker(){
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
//从程序当前运行线程中,随机取出一个线程出来干扰
Set<Thread> threads = Thread.getAllStackTraces().keySet();
int size = threads.size();
int i = 0;
int index = (int)(Math.random()*size);
for (Thread thread : threads) {
if(i!=index){
i++;
continue;
}
thread.interrupt();
break;
}
}
}
@Async
public void swimming(MySignal mySignal, String name){
SportEnum sportEnum = mySignal.getSport();
doSport(mySignal, name, sportEnum); //第一场比赛
rest(name);
sportEnum = mySignal.getSport();
doSport(mySignal, name, sportEnum); //第二场比赛
rest(name);
sportEnum = mySignal.getSport();
doSport(mySignal, name, sportEnum); //第三场比赛
boolean isWinner = mySignal.setWinner(name);
if(isWinner==true){
System.out.println("我是 "+name+", 我是冠军");
}
}
private void rest(String name){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println(name+" 休息10分钟");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
private void doSport(MySignal mySignal, String name, SportEnum sportEnum){
System.out.println(name +" 到达 "+sportEnum.getSportName()+" 起跑线,等待其他人");
while(sportEnum==mySignal.getSport()) {
try {
if(mySignal.getStartLine().isBroken()){
try{
Thread.sleep(0);
}catch (InterruptedException e){}
}else{
mySignal.getStartLine().await();
System.out.println(name + " 开始 " + sportEnum.getSportName());
}
} catch (InterruptedException e) {
System.out.println("我是"+name+",有人干扰我,在起跑线的人都重来");
mySignal.getStartLine().reset();
} catch (BrokenBarrierException e) {
System.out.println("我是"+name+",重新等待 "+sportEnum.getSportName());
}
}
}
}
定义程序入口函数,启动5个运动员和1个干扰者
package demo.cyclicbarrier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
final int size = 5;
TaskService taskService = context.getBean(TaskService.class);
MySignal mySignal = new MySignal(size);
for(int i=0;i<size;i++){
taskService.swimming(mySignal, "man"+i);
}
taskService.troublemaker();
context.close();
}
}
程序运行结果,可以看到,只有当所有运动员到达起跑线的时候,比赛才会开始
而且,如果在起跑线的运动员,如果被干扰了,会重置起跑线。
man0 到达 游泳 起跑线,等待其他人
man1 到达 游泳 起跑线,等待其他人
man3 到达 游泳 起跑线,等待其他人
man2 到达 游泳 起跑线,等待其他人
man4 到达 游泳 起跑线,等待其他人
游泳 比赛开始
man4 开始 游泳
man0 开始 游泳
man3 开始 游泳
man1 开始 游泳
man2 开始 游泳
man4 休息10分钟
man3 休息10分钟
man4 到达 跑步 起跑线,等待其他人
man2 休息10分钟
man1 休息10分钟
man0 休息10分钟
我是man4,有人干扰我,在起跑线的人都重来
man3 到达 跑步 起跑线,等待其他人
man1 到达 跑步 起跑线,等待其他人
man2 到达 跑步 起跑线,等待其他人
man0 到达 跑步 起跑线,等待其他人
跑步 比赛开始
man4 开始 跑步
man3 开始 跑步
man1 开始 跑步
man2 开始 跑步
man0 开始 跑步
man2 休息10分钟
man0 休息10分钟
man2 到达 骑车 起跑线,等待其他人
man4 休息10分钟
man3 休息10分钟
man1 休息10分钟
man4 到达 骑车 起跑线,等待其他人
man0 到达 骑车 起跑线,等待其他人
我是man2,有人干扰我,在起跑线的人都重来
我是man4,重新等待 骑车
我是man0,重新等待 骑车
我是man2,有人干扰我,在起跑线的人都重来
我是man4,重新等待 骑车
我是man0,重新等待 骑车
man3 到达 骑车 起跑线,等待其他人
man1 到达 骑车 起跑线,等待其他人
骑车 比赛开始
man2 开始 骑车
我是 man2, 我是冠军
man1 开始 骑车
man4 开始 骑车
man0 开始 骑车
man3 开始 骑车