多线程leetcode编程题



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();
        }
    }
    
}


下面这个解的重点是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();
                }
            }
        }
    }
}
相关推荐
神仙别闹42 分钟前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭1 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫1 小时前
泛型(2)
java
超爱吃士力架1 小时前
邀请逻辑
java·linux·后端
南宫生2 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石2 小时前
12/21java基础
java
李小白662 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp2 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
Lenyiin2 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
装不满的克莱因瓶3 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb