突发奇想的想写一个游戏组队的多线程实例,示例参考,多揪BUG 需求: 6人,10s 开局,overGame;
1 游戏线程
/**
* 游戏线程
*
* @author DeanKano
* @date 2018年3月17日
*/
public static class GamePlayingThread extends Thread {
// volatile并发可见性,保证同一时刻只有一个线程修改该变量
private volatile boolean overGame;
private long startTime = System.currentTimeMillis();
private String name;
private static final String ROOM_NAME_PREFIX = "R-";
private GamePlayingThread(String teamName, int roomNum) {
this.name = teamName + "(" + ROOM_NAME_PREFIX + roomNum + ")";
}
@Override
public void run() {
try {
while (!overGame) {
synchronized (this) {
wait(2000);
log.info("{}:游戏 ing...", this.name);
}
}
} catch (InterruptedException ex) {
log.error("{}:gameRunner interrupted !,exception:{}", this.name, ex);
} finally {
long recordTimes = getDiffSecondsFrom(this.startTime);
log.info("{}::gameRunner over !,用时:{}(s)", this.name, recordTimes);
}
}
public void overGame() {
this.overGame = true;
synchronized (this) {
notifyAll();
}
}
}
2 组队线程
/**
* 组队线程
*
* @author DeanKano
* @date 2018年3月17日
*/
public static class GameTeamThread extends Thread {
//倒计时(s)
private static final long MAX_COUNT_DOWN_SECONDS = 10;
// 是否可以组队
private volatile boolean allowTeam = true;
// 是否组队成功
private volatile boolean teamResult = false;
private Map<String, Boolean> playersMap;
private long startTime = System.currentTimeMillis();
private GamePlayingThread gameRunner;
private String name;
private static final String TEAM_NAME_PREFIX = "T-";
private AtomicInteger roomNum = new AtomicInteger(10000);
/**
* @param players 玩家
* @param teamNO 组队编号
*/
private GameTeamThread(@NonNull List<String> players, int teamNO) {
this.name = TEAM_NAME_PREFIX + teamNO;
this.playersMap = players.stream().collect(Collectors.toMap(a -> a, b -> false));
this.start();
}
/**
* 玩家确认
*/
private void readyOne(String playerName) {
playersMap.computeIfPresent(playerName, (k, v) -> true);
}
private boolean isAllReady() {
long countDownSeconds = getDiffSecondsFrom(this.startTime);
// 未超时并且都确认啦
return countDownSeconds <= MAX_COUNT_DOWN_SECONDS && !playersMap.values().contains(false);
}
@Override
public void run() {
try {
while (allowTeam) {
sleep(2000);
if (teamResult) {
log.info("{}:组队成功,开始游戏", this.name);
this.gameRunner = new GamePlayingThread(this.name, roomNum.incrementAndGet());
gameRunner.start();
break;
}
long countDownSeconds = getDiffSecondsFrom(this.startTime);
if (countDownSeconds > MAX_COUNT_DOWN_SECONDS) {
this.allowTeam = false;
log.info("{}:组队失败,{}(s)超时,有玩家未确认", this.name, MAX_COUNT_DOWN_SECONDS);
break;
}
if (isAllReady()) {
this.teamResult = true;
}
log.info("{} 用时:{}s,->组队信息:{}", this.name, countDownSeconds, this.playersMap.toString());
}
} catch (InterruptedException ex) {
log.error("{}:组队进程中断!,exception:{}", this.name, ex);
}
}
public void stopTeam() {
this.allowTeam = false;
synchronized (this) {
notifyAll();
}
}
}
3 调用demo
/**
* 6人,10s 开局,overGame;
* 示例:
* round1 (有玩家未确认,10s后组队失败)
* round2&round3 (玩家正常确认,正常在房间运行,游戏结束)
*/
public static void main(String[] args) throws InterruptedException {
AtomicInteger teamNO = new AtomicInteger(1000);
List<String> players = Arrays.asList("玩家A", "玩家B", "玩家C", "玩家D", "玩家E", "玩家F");
GameTeamThread round1 = new GameTeamThread(players, teamNO.incrementAndGet());
round1.readyOne("玩家A");
round1.readyOne("玩家C");
round1.readyOne("玩家E");
round1.readyOne("玩家F");
Thread.sleep(4000);
round1.readyOne("玩家D");
GameTeamThread round2 = new GameTeamThread(players, teamNO.incrementAndGet());
GameTeamThread round3 = new GameTeamThread(players, teamNO.incrementAndGet());
// 玩家正常确认
players.stream().forEach(round2::readyOne);
players.stream().forEach(round3::readyOne);
Thread.sleep(12000);
round2.gameRunner.overGame();
Thread.sleep(3000);
round3.gameRunner.overGame();
}
4 结果展示
14:23:59.918 [Thread-0] INFO cn.xiaolang.thread.GameDemo - T-1001 用时:2s,->组队信息:{玩家F=true, 玩家E=true, 玩家B=false, 玩家A=true, 玩家D=false, 玩家C=true}
14:24:01.926 [Thread-0] INFO cn.xiaolang.thread.GameDemo - T-1001 用时:4s,->组队信息:{玩家F=true, 玩家E=true, 玩家B=false, 玩家A=true, 玩家D=true, 玩家C=true}
14:24:03.914 [Thread-2] INFO cn.xiaolang.thread.GameDemo - T-1003 用时:2s,->组队信息:{玩家F=true, 玩家E=true, 玩家B=true, 玩家A=true, 玩家D=true, 玩家C=true}
14:24:03.914 [Thread-1] INFO cn.xiaolang.thread.GameDemo - T-1002 用时:2s,->组队信息:{玩家F=true, 玩家E=true, 玩家B=true, 玩家A=true, 玩家D=true, 玩家C=true}
14:24:03.926 [Thread-0] INFO cn.xiaolang.thread.GameDemo - T-1001 用时:6s,->组队信息:{玩家F=true, 玩家E=true, 玩家B=false, 玩家A=true, 玩家D=true, 玩家C=true}
14:24:05.917 [Thread-2] INFO cn.xiaolang.thread.GameDemo - T-1003:组队成功,开始游戏
14:24:05.917 [Thread-1] INFO cn.xiaolang.thread.GameDemo - T-1002:组队成功,开始游戏
14:24:05.930 [Thread-0] INFO cn.xiaolang.thread.GameDemo - T-1001 用时:8s,->组队信息:{玩家F=true, 玩家E=true, 玩家B=false, 玩家A=true, 玩家D=true, 玩家C=true}
14:24:07.922 [Thread-3] INFO cn.xiaolang.thread.GameDemo - T-1003(R-10001):游戏 ing...
14:24:07.922 [Thread-4] INFO cn.xiaolang.thread.GameDemo - T-1002(R-10001):游戏 ing...
14:24:07.934 [Thread-0] INFO cn.xiaolang.thread.GameDemo - T-1001 用时:10s,->组队信息:{玩家F=true, 玩家E=true, 玩家B=false, 玩家A=true, 玩家D=true, 玩家C=true}
14:24:09.926 [Thread-4] INFO cn.xiaolang.thread.GameDemo - T-1002(R-10001):游戏 ing...
14:24:09.926 [Thread-3] INFO cn.xiaolang.thread.GameDemo - T-1003(R-10001):游戏 ing...
14:24:09.938 [Thread-0] INFO cn.xiaolang.thread.GameDemo - T-1001:组队失败,有玩家未确认
14:24:11.927 [Thread-4] INFO cn.xiaolang.thread.GameDemo - T-1002(R-10001):游戏 ing...
14:24:11.928 [Thread-3] INFO cn.xiaolang.thread.GameDemo - T-1003(R-10001):游戏 ing...
14:24:13.915 [Thread-4] INFO cn.xiaolang.thread.GameDemo - T-1002(R-10001):游戏 ing...
14:24:13.916 [Thread-4] INFO cn.xiaolang.thread.GameDemo - T-1002(R-10001)::gameRunner over !,用时:7(s)
14:24:13.928 [Thread-3] INFO cn.xiaolang.thread.GameDemo - T-1003(R-10001):游戏 ing...
14:24:15.932 [Thread-3] INFO cn.xiaolang.thread.GameDemo - T-1003(R-10001):游戏 ing...
14:24:16.918 [Thread-3] INFO cn.xiaolang.thread.GameDemo - T-1003(R-10001):游戏 ing...
14:24:16.919 [Thread-3] INFO cn.xiaolang.thread.GameDemo - T-1003(R-10001)::gameRunner over !,用时:11(s)