多线程leetcode编程题

作者 : admin 本文共4266个字,预计阅读时间需要11分钟 发布时间: 2024-06-8 共4人阅读

多线程leetcode编程题插图
多线程leetcode编程题插图(1)
synchronized 实现

class ReentrantTest {
    private  int n;
    private volatile int flag = 1;
    private Object lock = new Object();

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

    public void zero(IntConsumer printNumber) throws InterruptedException{
        for(int i=1;i<=n;){
            synchronized (lock){
                if(flag%4==1 ||flag%4==3){
                    System.out.println(0);
                    flag++;
                    i++;
                    lock.notifyAll();
                } else{
                    lock.wait();
                }
            }
        }
    }

    public void odd(IntConsumer printNumber) throws InterruptedException {
        for(int i=1;i<=n;){
            synchronized (lock) {
             if(flag%4 == 2){
                 System.out.println(i);
                 i = i+2;
                 flag++;
                 lock.notifyAll();
             } else {
                 lock.wait();
             }
            }
        }
    }

    public void even(IntConsumer printNumber) throws InterruptedException{
        for(int i=2;i<=n;){
            synchronized (lock) {
                if(flag%4 == 0){
                    System.out.println(i);
                    i = i+2;
                    flag++;
                    lock.notifyAll();
                } else {
                    lock.wait();
                }
            }
        }
    }
}

ReentrantLock+Condition
下面为我第一遍写的错误例子
错误原因,假设先跑zero 线程,执行了 oddCondition.signalAll();后zeroCondition.await();,此时线程释放锁,而后才执行odd()线程,获取锁后oddCondition.await();,由于 .signal只能通知到已经在等待的线程,不能通知未来等待的线程,故,代码卡死了。

class ZeroEvenOdd {

    private  int n;
    private   ReentrantLock lock = new ReentrantLock();
    private  Condition zeroCondition = lock.newCondition();
    private  Condition evenCondition = lock.newCondition();
    private  Condition oddCondition = lock.newCondition();

    public ZeroEvenOdd(int n) {
        this.n = n;
    }
    
    public void zero() throws InterruptedException {

        for(int i=1;i<=n;i++){
            lock.lock();
            System.out.println(0);
            if(i%2==1){
                oddCondition.signalAll();
            } else {
                evenCondition.signalAll();
            }
            zeroCondition.await();
            lock.unlock();
        }
    }

    public void even() throws InterruptedException {

        for(int i=2;i<=n;){
            lock.lock();
            evenCondition.await();
            System.out.println(i);
            i=i+2;
            zeroCondition.signalAll();
            lock.unlock();
        }

    }

    public void odd() throws InterruptedException {
        for(int i=1;i<=n;){
            lock.lock();
            oddCondition.await();
            System.out.println(i);
            i=i+2;
            zeroCondition.signalAll();
            lock.unlock();
        }
    }

修改如下

 class ZeroEvenOdd {

    private  int n;
    private   ReentrantLock lock = new ReentrantLock();
    private  Condition zeroCondition = lock.newCondition();
    private  Condition evenCondition = lock.newCondition();
    private  Condition oddCondition = lock.newCondition();
    private volatile int flag = 1;

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

    public void zero() throws InterruptedException {

        for(int i=1;i<=n;){
            lock.lock();
            if(flag%4 ==1 || flag%4 == 3){
                System.out.println(0);
                flag++;
                i++;
                if(flag%4 ==0){
                    evenCondition.signal();
                } else {
                    oddCondition.signal();
                }
            } else {
                zeroCondition.await();
            }
            lock.unlock();
        }
    }

    //偶数
    public void even() throws InterruptedException {

        for(int i=2;i<=n;){
            lock.lock();
            if(flag%4 ==0){
                System.out.println(i);
                i=i+2;
                flag++;
                zeroCondition.signal();
            } else {
                evenCondition.await();
            }
            lock.unlock();
        }

    }

    //奇数
    public void odd() throws InterruptedException {
        for(int i=1;i<=n;){
            lock.lock();
            if(flag%4 == 2){
                System.out.println(i);
                i=i+2;
                flag++;
                zeroCondition.signal();
            } else {
                oddCondition.await();
            }
            lock.unlock();
        }
    }
    
}

多线程leetcode编程题插图(2)
多线程leetcode编程题插图(3)
下面这个解的重点是notify 和 notifyAll 的区别

notify和notifyAll的区别
首先讲这俩区别之前先来了解两个概念。锁池EntryList和等待池WaitSet。而这两个池和Object基类的notify

锁池
假设线程A已经拥有了某个对象(不是类)的锁,而其它线程B、C想要调用这个对象的某个synchronized方法(或者代码块), 由于B、C线程在进入对象的synchronized方法(或者块)之前必须先获得该对象锁的拥有权,而恰巧该对象的锁目前正被线程A所占用,此时B、C线程就会被阻塞,进入一个地方去等待锁的释放,这个地方便是该对象的锁池

等待池
假设线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁,同时线程A就进入到了该对象的等待池中,进入到等待池中的线程不会去竞争该对象的锁。

notifyAll会让所有处于等待池的线程全部进入锁池去竞争获取锁的机会
notify只会随机选取一个处于等待池中的线程进入锁池去竞争获取锁的机会

分析:
当current = 1时,执行number()里面,其他线程要么为执行,要么lock.wait();在等待池里,current =3时,number()进入等待池,由于 lock.notifyAll();唤醒了其他几个线程进入锁池,除了fizz满足条件,其他线程都执行了lock.wait();重新进入等待池。

class FizzBuzz {
    private int n;
    private final Object lock;
    private int current;

    public FizzBuzz(int n) {
        this.n = n;
        current = 1;
        lock = new Object();
    }

    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
        synchronized (lock) {
            while (current <= n) {
                if (current % 3 == 0 && current % 5 != 0) {
                    current++;
                    printFizz.run();
                    lock.notifyAll();
                } else {
                    lock.wait();
                }
            }
        }

    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        synchronized (lock) {
            while (current <= n) {
                if (current % 5 == 0 && current % 3 != 0) {
                    current++;
                    printBuzz.run();
                    lock.notifyAll();
                } else {
                    lock.wait();
                }
            }
        }

    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        synchronized (lock) {
            while (current <= n) {
                if (current % 15 == 0) {
                    current++;
                    printFizzBuzz.run();
                    lock.notifyAll();
                } else {
                    lock.wait();
                }
            }
        }
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
        synchronized (lock) {
            while (current <= n) {
                if (current % 3 != 0 && current % 5 != 0) {
                    printNumber.accept(current);
                    current++;
                    lock.notifyAll();
                } else {
                    lock.wait();
                }
            }
        }
    }
}
本站无任何商业行为
个人在线分享 » 多线程leetcode编程题
E-->