leetcode并发题解

 按序打印

解法一:使用volatile

public class FooWithVolatile {
    private volatile int count;

    public FooWithVolatile() {

    }

    public void first(Runnable printFirst) throws InterruptedException {
        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        count++;

    }

    public void second(Runnable printSecond) throws InterruptedException {
        // printSecond.run() outputs "second". Do not change or remove this line.
        while(count != 1) { }
        printSecond.run();
        count++;
    }

    public void third(Runnable printThird) throws InterruptedException {
    	while(count != 2) { }
        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();
    }
}

类似的,我们也可以使用AtomicInteger,不过其实AtomicInteger底层也是使用了volatile字段,只不过在计算时会使用CAS解决原子性问题,但是这里的while循环对自增操作进行了阻塞,所以不会出现三个线程同时对count自增的情况,所以没必要使用AtomicInteger,更何况CAS操作里面的while循环也是很耗费资源的

解法二:使用CountDownLatch

public class FooWithCountDownLatch {
    private CountDownLatch second = new CountDownLatch(1);
    private CountDownLatch third = new CountDownLatch(1);

    public FooWithCountDownLatch() {
    }

    public void first(Runnable printFirst) throws InterruptedException {
        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        second.countDown();
    }

    public void second(Runnable printSecond) throws InterruptedException {
    	second.await();
        // printSecond.run() outputs "second". Do not change or remove this line.
        printSecond.run();
        third.countDown();
    }

    public void third(Runnable printThird) throws InterruptedException {
    	third.await();
        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();
    }
}

类似的,这里我们使用两个“门栓”栓住(阻塞)second方法和third方法执行run方法打印结果,当first方法执行完毕后,释放second的门栓让second方法打印结果,second方法执行完毕后,释放third的门栓让third方法打印结果


交替打印FooBar

在这里插入图片描述

class FooBarWithCountDownLatch {
    private int n;
    private CountDownLatch fooLatch = new CountDownLatch(0);
    private CountDownLatch barLatch = new CountDownLatch(1);

    public FooBarWithCountDownLatch(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {

        for (int i = 0; i < n; i++) {
            fooLatch.await();
            // printFoo.run() outputs "foo". Do not change or remove this line.
            printFoo.run();
            fooLatch = new CountDownLatch(1);
            barLatch.countDown();
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {

        for (int i = 0; i < n; i++) {
            barLatch.await();
            // printBar.run() outputs "bar". Do not change or remove this line.
            printBar.run();
            barLatch = new CountDownLatch(1);
            fooLatch.countDown();
        }
    }
}

这里要注意,CountDownLatch和CyclicBarrier不一样,CountDownLatch是一次性的,countDown到0之后不会自己恢复成1,所以要每次new一个CountDownLatch对象。


打印零与奇偶数

在这里插入图片描述

public class ZeroEvenOdd {
    private int n;
    private CountDownLatch zero = new CountDownLatch(0);
    private CountDownLatch even = new CountDownLatch(1);
    private CountDownLatch odd = new CountDownLatch(1);

    public ZeroEvenOdd(int n) {
        this.n = n;
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void zero(IntConsumer printNumber) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            zero.await();
            printNumber.accept(0);
            zero = new CountDownLatch(1);
            if(i % 2 == 0) {
                odd.countDown();
            } else {
                even.countDown();
            }
        }
        
    }

    public void even(IntConsumer printNumber) throws InterruptedException {
        for (int i = 2; i < n; i+=2) {
            even.await();
            printNumber.accept(i);
            even = new CountDownLatch(1);
            zero.countDown();
        }

    }

    public void odd(IntConsumer printNumber) throws InterruptedException {
        for (int i = 1; i < n; i+=2) {
            odd.await();
            printNumber.accept(i);
            odd = new CountDownLatch(1);
            zero.countDown();
        }
    }
}

这道题没什么好说的,做法也同样很多样,只要仔细点,都可以做对,但是我感觉都没直接用CoutDownLatch好。


H2O

在这里插入图片描述

public class H2O {
    private Semaphore hSemaphore = new Semaphore(2);
    private Semaphore oSemaphore = new Semaphore(0);

    public H2O() {

    }

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

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

实在想不到Semaphore以外的做法,虽然看题解确实有,但是反而不怎么好

原文地址:https://www.cnblogs.com/fatmanhappycode/p/12231194.html