0
0

Java Gold 例題 同期制御2

Last updated at Posted at 2024-08-14
class StudentExamination {

	private static final int NUM_STUDENTS = 3;
	private static final int NUM_QUESTIONS = 5;
	private static final int MAX_TIME_PER_QUESTION = 10;
	
	public static void main(String[] args) {
		ExecutorService executorService = Executors.newFixedThreadPool(NUM_STUDENTS);
		
		CyclicBarrier barrier = new CyclicBarrier(NUM_STUDENTS, new Runnable() {
			private int currentQuestion = 0;
			@Override
			public void run() {
				currentQuestion++;
				if(currentQuestion <= NUM_QUESTIONS) {
					System.out.println("全員が問題" + currentQuestion + "に正解しました。");
					if(currentQuestion == NUM_QUESTIONS) {
						System.out.println("全問クリア。テストが終了しました。");
						executorService.shutdown();
					}
				}
			}
		});
		
		for(int i = 0; i < NUM_STUDENTS; i++) {
			final int studentId = i + 1;
			executorService.submit(() -> {
				try {
					for(int question = 1; question <= NUM_QUESTIONS; question++) {
						
						int answerTime = (int)(Math.random() * (MAX_TIME_PER_QUESTION + 2)) + 1;
						TimeUnit.SECONDS.sleep(answerTime);
						
						if(answerTime <= MAX_TIME_PER_QUESTION) {
							System.out.println("生徒 " + studentId + " は問題 " + question + "に" + answerTime + "秒で正解しました。");
						} else {
							System.out.println("生徒 " + studentId + "が問題" + question + " で時間切れです。");
							executorService.shutdown();
							break;
						}
						
						barrier.await();
					}
				} catch(InterruptedException | BrokenBarrierException e) {
					System.out.println("error");
				}
			});
		}
	}
}

本コード実行後、終了時点の出力結果として当てはまらないものを1つ選んでください。

A

生徒 1 は問題 1に3秒で正解しました。
生徒 3 は問題 1に10秒で正解しました。
生徒 2が問題1 で時間切れです。

B

生徒 3 は問題 1に4秒で正解しました。
生徒 1 は問題 1に4秒で正解しました。
生徒 2 は問題 1に5秒で正解しました。
全員が問題1に正解しました。
生徒 1 は問題 2に2秒で正解しました。
生徒 2 は問題 2に2秒で正解しました。
生徒 3 は問題 2に8秒で正解しました。
全員が問題2に正解しました。
生徒 1 は問題 3に1秒で正解しました。
生徒 3が問題3 で時間切れです。
生徒 2が問題3 で時間切れです。

C

生徒 1 は問題 1に3秒で正解しました。
生徒 3が問題1 で時間切れです。
生徒 2が問題1 で時間切れです。

D

生徒 3が問題1 で時間切れです。
生徒 1が問題1 で時間切れです。
生徒 2が問題1 で時間切れです。

E

生徒 2 は問題 1に5秒で正解しました。
生徒 3 は問題 1に6秒で正解しました。
生徒 1 は問題 1に9秒で正解しました。
全員が問題1に正解しました。
生徒 2 は問題 2に3秒で正解しました。
生徒 3 は問題 2に7秒で正解しました。
生徒 1 は問題 2に10秒で正解しました。
全員が問題2に正解しました。
生徒 2 は問題 3に1秒で正解しました。
生徒 3 は問題 3に3秒で正解しました。
生徒 1 は問題 3に7秒で正解しました。
全員が問題3に正解しました。

E

本コードの概要
3人の生徒が5問の問題に挑戦し、1問ごとに全員が正解すると次の問題に進みます。
各生徒の回答時間はランダムに生成されます。
10秒内に全員が正解できなかった場合、その問題でゲームオーバーになります。

選択肢
A B C D
一人でも時間切れになるとゲームオーバーです。
一人でも時間切れになるとその問題の生徒全員の結果が出力された後終了します。

E:
問題 3で全員が正解していますが、その後全員が問題 4に進まなければならないのに、その記述がありません。よってEが不正解です。

補足

このコードは、ExecutorServiceを使って並行して問題に取り組む生徒をシミュレートし、CyclicBarrierを使って全員が問題に正解するまで待機させることで、次の問題に進むまで待機します。
sleep()を使って解答時間をシミュレートし、1人でも時間切れになるとテストが終了します。

定数

NUM_STUDENTS 生徒の数(3人)。
NUM_QUESTIONS 問題の数(5問)。
MAX_TIME_PER_QUESTION 各問題に対する最大解答時間(10秒)。

ExecutorService executorService = Executors.newFixedThreadPool(NUM_STUDENTS);

3つのスレッドを持つスレッドプールを作成します。
これにより、3人の生徒が並行して問題に取り組むことができます。

CyclicBarrier barrier = new CyclicBarrier(NUM_STUDENTS, new Runnable() {...

CyclicBarrierは全ての生徒が同じ問題を解き終えるまで待機するために使用されます。
全員がbarrier.await()に到達すると、CyclicBarrierRunnableが呼ばれ、次の問題に進む処理が行われます。

int answerTime = (int)(Math.random() * (MAX_TIME_PER_QUESTION + 2)) + 1; //1 ~ 12
TimeUnit.SECONDS.sleep(answerTime);

各生徒は、1問ごとにランダムな解答時間で解答します。
TimeUnit.SECONDS.sleep(answerTime)で解答時間をシミュレートします。
解答時間がMAX_TIME_PER_QUESTION秒以内であれば、「正解しました」と表示します。
超えると「時間切れです」と表示し、executorService.shutdown()で全スレッドを終了させます。

barrier.await()で全員が正解すると、CyclicBarrierRunnableが実行され、次の問題に進みます。

全ての問題に正解すると、「全問クリア。テストが終了しました。」と表示され、スレッドプールがシャットダウンします。

Document
Executors
ExecutorService
CyclicBarrier
TimeUnit

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0