多线程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();
                }
            }
        }
    }
}
相关推荐
lingRJ7771 分钟前
微服务架构下的抉择:Consul vs. Eureka,服务发现该如何选型?
java·eureka·springcloud·consul·backend·microservices·servicediscovery
RainbowSea1 分钟前
问题:后端由于字符内容过长,前端展示精度丢失修复
java·spring boot·后端
C182981825754 分钟前
OOM电商系统订单缓存泄漏,这是泄漏还是溢出
java·spring·缓存
风象南18 分钟前
SpringBoot 控制器的动态注册与卸载
java·spring boot·后端
我是一只代码狗44 分钟前
springboot中使用线程池
java·spring boot·后端
hello早上好1 小时前
JDK 代理原理
java·spring boot·spring
PanZonghui1 小时前
Centos项目部署之Java安装与配置
java·linux
沉着的码农2 小时前
【设计模式】基于责任链模式的参数校验
java·spring boot·分布式
Mr_Xuhhh2 小时前
信号与槽的总结
java·开发语言·数据库·c++·qt·系统架构
纳兰青华2 小时前
bean注入的过程中,Property of ‘java.util.ArrayList‘ type cannot be injected by ‘List‘
java·开发语言·spring·list