多线程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();
                }
            }
        }
    }
}
相关推荐
wkj0019 分钟前
接口实现类向上转型和向上转型解析
java·开发语言·c#
qqxhb10 分钟前
零基础设计模式——行为型模式 - 观察者模式
java·观察者模式·设计模式·go
寒士obj37 分钟前
类加载的过程
java·开发语言
无名之逆40 分钟前
大三自学笔记:探索Hyperlane框架的心路历程
java·开发语言·前端·spring boot·后端·rust·编程
Chuck1sn42 分钟前
我把 Cursor AI 整合到 Ruoyi 中,从此让 Java 脚手架脱离人工!
java·vue.js·后端
水木石画室1 小时前
Spring Boot 常用注解面试题深度解析
java·spring boot·后端
hweiyu001 小时前
tomcat指定使用的jdk版本
java·开发语言·tomcat
百锦再1 小时前
.NET 类库开发详细指南c
java·log4j·.net·net·dot
黎䪽圓2 小时前
【Java多线程从青铜到王者】阻塞队列(十)
java·开发语言