• 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以外的做法,虽然看题解确实有,但是反而不怎么好

  • 相关阅读:
    【python】变量定义及全局局部变量
    【python】重要的内置函数
    【python】迭代器iterator
    Java序列化与反序列化
    java中的IO操作总结
    Java中List Set Map 是否有序等总结
    java.lang.Class.getDeclaredMethod()方法详解
    一个servlet处理多个请求(使用Method的反射机制)
    java类的访问权限
    java中的基本数据类型存放位置
  • 原文地址:https://www.cnblogs.com/fatmanhappycode/p/12231194.html
Copyright © 2020-2023  润新知