結城浩のはてなブログ

ふと思いついたことをパタパタと書いてます。

サンタクロース問題を解く(Java)

サンタクロース問題Javaで書いてみました(via サンタクロース問題を Squeak Smalltalk で)。Golfではありません。
…プログラムを書いてから問題を読み直したら、問題を読み違えてた(>_<)。こびとさんは10人いるのか。ふえーん。でもいいや、公開しちゃうもん。

import java.util.concurrent.*;
import java.util.*;

class Santa extends Thread {
    private static final int REINDEER_NUM = 9;
    private static final int ELF_NUM = 3;

    private boolean _readyAllElvesToWork = false;
    private boolean _readyAllReindeersToWork = false;

    private final CyclicBarrier _elfWorkBarrier = new CyclicBarrier(ELF_NUM, new Runnable() {
        public void run() {
            notifyAllElvesAreReadyToWork();
        }
    });

    private final CyclicBarrier _reindeerWorkBarrier = new CyclicBarrier(REINDEER_NUM, new Runnable() {
        public void run() {
            notifyAllReindeersAreReadyToWork();
        }
    });

    private final CyclicBarrier _elfPlayBarrier = new CyclicBarrier(ELF_NUM + 1);
    private final CyclicBarrier _reindeerPlayBarrier = new CyclicBarrier(REINDEER_NUM + 1);

    public static void main(String[] args) {
        new Santa().start();
    }

    public void run() {
        startAllWorkers();
        try {
            synchronized (this) {
                while (true) {
                    while (!_readyAllElvesToWork && !_readyAllReindeersToWork) {
                        wait();
                    }
                    if (_readyAllReindeersToWork) {
                        _readyAllReindeersToWork = false;
                        _reindeerPlayBarrier.await();
                    }
                    if (_readyAllElvesToWork) {
                        _readyAllElvesToWork = false;
                        _elfPlayBarrier.await();
                    }
                }
            }
        } catch (InterruptedException e) {
        } catch (BrokenBarrierException e) {
        }
    }

    private void startAllWorkers() {
        for (int i = 0; i < ELF_NUM; i++) {
            new Worker("Elf No." + i, _elfWorkBarrier, _elfPlayBarrier).start();
        }
        for (int i = 0; i < REINDEER_NUM; i++) {
            new Worker("Reindeer No." + i, _reindeerWorkBarrier, _reindeerPlayBarrier).start();
        }
    }

    private synchronized void notifyAllElvesAreReadyToWork() {
        System.out.println("All elves are ready to work!");
        _readyAllElvesToWork = true;
        notifyAll();
    }

    private synchronized void notifyAllReindeersAreReadyToWork() {
        System.out.println("All reindeers are ready to work!");
        _readyAllReindeersToWork = true;
        notifyAll();
    }
}

class Worker extends Thread {
    private static final Random _random = new Random();
    private final CyclicBarrier _workBarrier;
    private final CyclicBarrier _playBarrier;

    public Worker(String name, CyclicBarrier workBarrier, CyclicBarrier playBarrier) {
        super(name);
        _workBarrier = workBarrier;
        _playBarrier = playBarrier;
        System.out.println(this + " is born.");
    }

    public void run() {
        try {
            while (true) {
                work();
                play();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

    private void work() throws InterruptedException, BrokenBarrierException {
        System.out.println(this + " is waiting to work.");
        _workBarrier.await();
        randomSleep();
    }

    private void play() throws InterruptedException, BrokenBarrierException {
        System.out.println(this + " is waiting to play.");
        _playBarrier.await();
        randomSleep();
    }

    public void randomSleep() throws InterruptedException {
        Thread.sleep(_random.nextInt(1000));
    }
}