拉不拉稀肚拉稀 发表于 2024-6-20 15:03:11

多线程leetcode编程题

https://img-blog.csdnimg.cn/direct/f32e4cc764084987a6a7fe30868855c0.png
https://img-blog.csdnimg.cn/direct/3042b4834c8e4f84b080a09d3280edec.png
synchronized 实现
class ReentrantTest {
    privateint 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 {

    privateint n;
    private   ReentrantLock lock = new ReentrantLock();
    privateCondition zeroCondition = lock.newCondition();
    privateCondition evenCondition = lock.newCondition();
    privateCondition 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 {

    privateint n;
    private   ReentrantLock lock = new ReentrantLock();
    privateCondition zeroCondition = lock.newCondition();
    privateCondition evenCondition = lock.newCondition();
    privateCondition 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();
      }
    }
   
}
https://img-blog.csdnimg.cn/direct/87274a0291944dd9bf4c5980b2af4b2a.png
https://img-blog.csdnimg.cn/direct/f3a7cb5199fe45ca8354531144234471.png
下面这个解的重点是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();
                }
            }
      }
    }
}

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 多线程leetcode编程题