leetcode 多线程题集

745 阅读3分钟

1. 按序打印

  1. 方法1:无锁的方法:使用volatile+自旋
class Foo {
    volatile int flag;
    public Foo() {
        
    }

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

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

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

方法一的volatile变量也可以换成原子自增类AtomicInteger。

这里因为没有多线程同时写,所以flag++也可以。

方法2:使用信号量

    private Semaphore two = new Semaphore(0);
    private Semaphore three = new Semaphore(0);

    public Foo() {

    }

    public void first(Runnable printFirst) throws InterruptedException {

        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        two.release();
    }

    public void second(Runnable printSecond) throws InterruptedException {
        two.acquire();
        // printSecond.run() outputs "second". Do not change or remove this line.
        printSecond.run();
        three.release();
    }

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

方法3 使用条件变量/wait, notifyAll

class Foo {
    int  flag;
    public Foo() {
    }

    public void first(Runnable printFirst) throws InterruptedException {
        
        // printFirst.run() outputs "first". Do not change or remove this line.
        synchronized(this) {
            printFirst.run();
            flag = 1;
            notifyAll();
        }
        
    }

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

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

方法3可能写出错误的代码,注意点1:必须得加一个flag防止调度时线程1先执行唤醒,线程2然后在wait。这样线程2将永远沉睡。注意点2:flag变量的更新必须在notifyAll()前面。

方法4: 使用CountDownLatch与CyclicBarrier也可以。但是得设置2个,此处不表。

1115

方法1:无锁

class FooBar {
    private int n;
    int flag = 1;
    public FooBar(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        
        for (int i = 0; i < n; i++) {
            while (flag != 1) {
                Thread.yield();
            }
        	// printFoo.run() outputs "foo". Do not change or remove this line.
        	printFoo.run();
            flag = 2;
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {
        
        for (int i = 0; i < n; i++) {
            while (flag != 2) {
                Thread.yield();
            }
            // printBar.run() outputs "bar". Do not change or remove this line.
        	printBar.run();
            flag = 1;
        }
    }
}

方法2:使用2个信号量

class FooBar {
    private int n;
    Semaphore f = new Semaphore(1);
    Semaphore b = new Semaphore(0);
    public FooBar(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        
        for (int i = 0; i < n; i++) {
            
        	// printFoo.run() outputs "foo". Do not change or remove this line.
            f.acquire();
        	printFoo.run();
            b.release();
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {
        
        for (int i = 0; i < n; i++) {
            
            // printBar.run() outputs "bar". Do not change or remove this line.
            b.acquire();
        	printBar.run();
            f.release();
        }
    }
}

其他方法,条件变量,CountDownLatch, CyclicBarrier。不赘述

1116. 打印零与奇偶数

自旋

class ZeroEvenOdd {
    private int n;
    volatile int zero = 1, flag = -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++) {
            while (zero != 1) {
                Thread.yield();
            }
            printNumber.accept(0);
            zero = 0;
            flag ++;
        }
    }

    public void even(IntConsumer printNumber) throws InterruptedException {
        for (int i = 2; i <= n; i += 2) {
            while (flag != 2) {
                Thread.yield();
            }
            printNumber.accept(i);
            flag = -1;
            zero = 1;
        }
    }

    public void odd(IntConsumer printNumber) throws InterruptedException {
        for (int i = 1; i <= n; i += 2) {
            while (flag != 0) {
                Thread.yield();
            }
            printNumber.accept(i);
            flag = 1;
            zero = 1;
        }
    }
}

条件变量

与无锁几乎没区别。只是把自旋换成了阻塞。

class ZeroEvenOdd {
    private int n;
    volatile int zero = 1, flag = -1;
    public ZeroEvenOdd(int n) {
        this.n = n;
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public synchronized void zero(IntConsumer printNumber) throws InterruptedException {
        
        for (int i = 0; i < n; i++) {
            while (zero != 1) {
                wait();
            }
            printNumber.accept(0);
            zero = 0;
            flag ++;
            notifyAll();
        }
    }

    public synchronized void even(IntConsumer printNumber) throws InterruptedException {
        for (int i = 2; i <= n; i += 2) {
            while (flag != 2) {
                wait();
            }
            printNumber.accept(i);
            flag = -1;
            zero = 1;
            notifyAll();
        }
    }

    public synchronized void odd(IntConsumer printNumber) throws InterruptedException {
        for (int i = 1; i <= n; i += 2) {
            while (flag != 0) {
                wait();
            }
            printNumber.accept(i);
            flag = 1;
            zero = 1;
            notifyAll();
        }
    }
}

1117. H2O 生成

无锁方式没写出来,应该没有办法无锁。

class H2O {
    Semaphore h = new Semaphore(2);
    Semaphore o = new Semaphore(0);
    public H2O() {
        
    }

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

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