H2O 生成

题目 #

1117. H2O 生成 #

现在有两种线程,氧 oxygen 和氢 hydrogen,你的目标是组织这两种线程来产生水分子。

存在一个屏障(barrier)使得每个线程必须等候直到一个完整水分子能够被产生出来。

氢和氧线程会被分别给予 releaseHydrogenreleaseOxygen 方法来允许它们突破屏障。

这些线程应该三三成组突破屏障并能立即组合产生一个水分子。

你必须保证产生一个水分子所需线程的结合必须发生在下一个水分子产生之前。

换句话说:

  • 如果一个氧线程到达屏障时没有氢线程到达,它必须等候直到两个氢线程到达。
  • 如果一个氢线程到达屏障时没有其它线程到达,它必须等候直到一个氧线程和另一个氢线程到达。

书写满足这些限制条件的氢、氧线程同步代码。

示例 1:

输入: water = "HOH"
输出: "HHO"
解释: "HOH" 和 "OHH" 依然都是有效解。

示例 2:

输入: water = "OOHHHH"
输出: "HHOHHO"
解释: "HOHHHO", "OHHHHO", "HHOHOH", "HOHHOH", "OHHHOH", "HHOOHH", "HOHOHH" 和 "OHHOHH" 依然都是有效解。

提示:

  • 3 * n == water.length
  • 1 <= n <= 20
  • water[i] == 'O' or 'H'
  • 输入字符串 water 中的 ‘H’ 总数将会是 2 * n
  • 输入字符串 water 中的 ‘O’ 总数将会是 n

解答 #

方法1 使用semaphore #

H2OH_2O 来说,两个H和一个O之后才可以开始下一次

可以使用Semaphore来做

  • 其中H的Semaphore初始为2
  • O的Semaphore初始为0
  • 在运行时,先运行H,两次,然后再运行O一次
class H2O {
    Semaphore o;
    Semaphore h;
    public H2O() {
        o=new Semaphore(0);
        h=new Semaphore(2);
    }

    public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
        h.acquire();
        // releaseHydrogen.run() outputs "H". Do not change or remove this line.
        releaseHydrogen.run();
        o.release();
    }

    public void oxygen(Runnable releaseOxygen) throws InterruptedException {
        o.acquire(2);
        // releaseOxygen.run() outputs "O". Do not change or remove this line.
		releaseOxygen.run();
        h.release(2);
    }
}

方法2 使用Semaphore+CyclicBarrier #

CyclicBarrier用于实现3个线程(2H+1O)进行等待,到齐之后再同时进行操作,然后释放信号量

注意CyclicBarrier的方法**是await()**不是wait(),wait是Object的方法

class H2O {
    private Semaphore hSema = new Semaphore(2);
    private Semaphore oSema = new Semaphore(1);
    private CyclicBarrier cb = new CyclicBarrier(3);

    public H2O() {

    }

    public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
        hSema.acquire();
        try {
            cb.await();//来一个线程,就在这个地方等着,最多两个线程等着,因为hSema有限
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        releaseHydrogen.run();
        hSema.release(); //一个线程,释放一个 Semaphore+1
    }

    public void oxygen(Runnable releaseOxygen) throws InterruptedException {
        oSema.acquire();
        try {
            cb.await();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        releaseOxygen.run();
        oSema.release();
    }
}