用线程模拟,CountDownLatch,CyclicBarrier

本文通过模拟比赛场景,对比了使用synchronized、CountDownLatch和CyclicBarrier三种不同方式来控制多个线程(模拟运动员)的同步开始及结束过程。通过具体代码示例展示了不同同步工具的特点及其适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前从网上看到一段代码,关于wait和notify的,但是发现代码写的有bug,并且程序的逻辑我感觉并不是太清楚,但是程序所举的例子还是很有意义的。


因此我改写了一下,用面向对象的思维。



import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 用于模拟在一个game中先让运动员全体准备好,然后一起开始game
 * 
 * @author donggua
 * 
 */
public class Game {

	public static AtomicInteger readPlayerCount = new AtomicInteger(0);// 运动员的数量

	private Set<Athlete> players = new HashSet<Athlete>();// 用于存放运动员,表示参与这个game的集合

	public void addPlayer(Athlete one) {
		players.add(one);
	}

	public void removePlayer(Athlete one) {
		players.remove(one);
	}

	public Collection<Athlete> getPlayers() {
		return Collections.unmodifiableSet(players);
	}

	/**
	 * game的准备阶段,表示通知所有的运动员准备好
	 */
	public void prepare() {
		for (Athlete player : players) {
			player.ready();
		}
	}

	/**
	 * game开始,通知所有的运动员开始
	 */
	public void go() {
		synchronized (Game.class) {
			Game.class.notifyAll();
		}
	}

	public static void main(String[] args) {
		Game game = new Game();
		for (int i = 0; i < 10; i++) {
			game.addPlayer(new Athlete(i));
		}
		game.prepare();

		while (true) {
			if (readPlayerCount.get() == 10) {// 所有的运动员准备好之后,game开始
				game.go();
				break;
			}
		}
	}
}



/**
 * 运动员实体类
 * 
 * @author donggua
 * 
 */
class Athlete implements Runnable {

	private final int id;

	public Athlete(int id) {
		this.id = id;
	}

	public String toString() {
		return "Athlete<" + id + ">";
	}

	public void ready() {
		new Thread(this).start();
	}

	public void run() {
		synchronized (Game.class) {
			try {
				Game.readPlayerCount.addAndGet(1);
				System.out.println(this + " ready!");
				Game.class.wait();
				System.out.println(this + "go");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}





上面是用到了synchronized,notifyAll ,wait等java原生的方式实现了这一功能,但是jdk中还是提供了更加面向对象的实现如:CountDownLatch 和CyclicBarrier

下面就用这两个类分别改写上面的程序:


import java.util.concurrent.CountDownLatch;

/**
 * 运动员实体类
 * 
 * @author donggua
 * 
 */
class AthleteCountDownLatch implements Runnable {

	private int id;
	private CountDownLatch startSignal;
	private CountDownLatch doneSignal;

	AthleteCountDownLatch(CountDownLatch startSignal, CountDownLatch doneSignal, int id) {
		this.startSignal = startSignal;
		this.doneSignal = doneSignal;
		this.id = id;
	}

	public AthleteCountDownLatch(int id) {
		this.id = id;
	}

	public String toString() {
		return "Athlete<" + id + ">";
	}

	public void ready() {
		new Thread(this).start();
	}

	public void run() {
		try {
			GameCountLatch.readPlayerCount.addAndGet(1);
			System.out.println(this.toString() + "ready。。。");
			startSignal.await();
			doWork();
			doneSignal.countDown();
		} catch (InterruptedException ex) {

		}

	}

	private void doWork() {
		System.out.println(toString() + "game 进行中。。。。。");
	}
}




import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 用于模拟在一个game中先让运动员全体准备好,然后一起开始game
 * 
 * @author donggua
 * 
 */
public class GameCountLatch {

	public static AtomicInteger readPlayerCount = new AtomicInteger(0);// 运动员的数量

	private Set<AthleteCountDownLatch> players = new HashSet<AthleteCountDownLatch>();// 用于存放运动员,表示参与这个game的集合

	public void addPlayer(AthleteCountDownLatch one) {
		players.add(one);
	}

	/**
	 * game的准备阶段,表示通知所有的运动员准备好
	 */
	public void prepare(CountDownLatch startSignal, CountDownLatch doneSignal, GameCountLatch game) {
		for (int i = 0; i < 10; i++) {
			game.addPlayer(new AthleteCountDownLatch(startSignal, doneSignal, i));
		}
		for (AthleteCountDownLatch player : players) {
			player.ready();
		}
	}

	/**
	 * game开始,通知所有的运动员开始
	 */
	public void go(CountDownLatch startSignal) {
		while (true) {
			if (readPlayerCount.get() == 10) {// 所有的运动员准备好之后,game开始
				startSignal.countDown();
				break;
			}
		}

	}

	public static void main(String[] args) {

		CountDownLatch startSignal = new CountDownLatch(1);
		CountDownLatch endSignal = new CountDownLatch(10);
		GameCountLatch game = new GameCountLatch();

		game.prepare(startSignal, endSignal, game);
		game.go(startSignal);

		try {
			endSignal.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("game 结束");

	}
}


可以看到上面的程序比上上个稍微好一点,关键的是能够得到game结束的时机点。


import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * 运动员实体类
 * 
 * @author donggua
 * 
 */
class AthleteCyclicBarrier implements Runnable {

	private final int id;
	private CyclicBarrier barrier;

	public AthleteCyclicBarrier(CyclicBarrier barrier, int id) {
		this.barrier = barrier;
		this.id = id;
	}

	public String toString() {
		return "Athlete<" + id + ">";
	}

	public void readyAndGo() {
		new Thread(this).start();
	}

	public void run() {
		synchronized (barrier) {
			System.out.println(toString() + " ready!  已经有" + (barrier.getNumberWaiting() + 1) + "个准备好了");
		}
		try {
			barrier.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}

		System.out.println(toString() + " gameing ...!");

		try {
			barrier.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}

	}
}

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * 用于模拟在一个game中先让运动员全体准备好,然后一起开始game
 * @author donggua
 *
 */
public class GameCyclicBarrier {

	public static AtomicInteger readPlayerCount = new AtomicInteger(0);//运动员的数量
	private Set<AthleteCyclicBarrier> players = new HashSet<AthleteCyclicBarrier>();//用于存放运动员,表示参与这个game的集合

	public void addPlayer(AthleteCyclicBarrier one) {
		players.add(one);
	}

	/**
	* game的准备阶段,表示通知所有的运动员准备好
	*/
	public void readyAndGo(CyclicBarrier barrier,GameCyclicBarrier game) {
		for (int i = 0; i < 10; i++) {
			game.addPlayer(new AthleteCyclicBarrier(barrier,i));
		}
		for(AthleteCyclicBarrier player : players) {
			player.readyAndGo();
		}
	}

	public static void main(String[] args) {
		CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
		GameCyclicBarrier game = new GameCyclicBarrier();
		game.readyAndGo(cyclicBarrier, game);
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值