Leetcode多线程题目汇总

1114. 按序打印

多种解法,都是多线程常用工具

volite:

class Foo {
    private volatile int flag=-1;
//    private AtomicInteger firstJobDone = new AtomicInteger(0);
   
    public Foo() {}

    public void first(Runnable printFirst) throws InterruptedException {
        // printFirst.run() outputs "first".
        printFirst.run();
        // mark the first job as done, by increasing its count.
        flag=1;
    }

    public void second(Runnable printSecond) throws InterruptedException {
        while (flag != 1) {
            // waiting for the first job to be done.
        }
        // printSecond.run() outputs "second".
        printSecond.run();
        // mark the second as done, by increasing its count.
        flag=2;
    }

    public void third(Runnable printThird) throws InterruptedException {
        while (flag != 2) {
            // waiting for the second job to be done.
        }
        // printThird.run() outputs "third".
        printThird.run();
    }
}

原子类:

class Foo {

    private AtomicInteger firstJobDone = new AtomicInteger(0);
    private AtomicInteger secondJobDone = new AtomicInteger(0);

    public Foo() {}

    public void first(Runnable printFirst) throws InterruptedException {
        // printFirst.run() outputs "first".
        printFirst.run();
        // mark the first job as done, by increasing its count.
        firstJobDone.incrementAndGet();
    }

    public void second(Runnable printSecond) throws InterruptedException {
        while (firstJobDone.get() != 1) {
            // waiting for the first job to be done.
        }
        // printSecond.run() outputs "second".
        printSecond.run();
        // mark the second as done, by increasing its count.
        secondJobDone.incrementAndGet();
    }

    public void third(Runnable printThird) throws InterruptedException {
        while (secondJobDone.get() != 1) {
            // waiting for the second job to be done.
        }
        // printThird.run() outputs "third".
        printThird.run();
    }
}

阻塞队列:

class Foo {

    BlockingQueue queue=new ArrayBlockingQueue(1);
    BlockingQueue queue1=new ArrayBlockingQueue(1);


    public Foo() {

    }

    public void first(Runnable printFirst) throws InterruptedException {
        System.out.println("111");
        printFirst.run();
        queue.add(1);



    }

    public void second(Runnable printSecond) throws InterruptedException {
        queue.take();
        System.out.println("222");
        printSecond.run();
        queue1.add(2);
        queue.add(3);

    }

    public void third(Runnable printThird) throws InterruptedException {
        queue1.take();
        System.out.println("333");
        queue.take();
        printThird.run();
    }
}

计时器:

class Foo {
    private CountDownLatch second=new CountDownLatch(1);
    private CountDownLatch three=new CountDownLatch(1);
    public Foo() {

    }

    public void first(Runnable printFirst) throws InterruptedException {

        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        second.countDown();
    }

    public void second(Runnable printSecond) throws InterruptedException {
        second.await();
        // printSecond.run() outputs "second". Do not change or remove this line.
        printSecond.run();
        three.countDown();
    }

    public void third(Runnable printThird) throws InterruptedException {
        three.await();
        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();

    }
}

信号量:

class Foo {
       public Semaphore seam_first_two = new Semaphore(0);
    
    public Semaphore seam_two_second = new Semaphore(0);
     

    public Foo() {

    }

    public void first(Runnable printFirst) throws InterruptedException {
       
        printFirst.run();
         seam_first_two.release();
        
         

    }

    public void second(Runnable printSecond) throws InterruptedException {
        seam_first_two.acquire();
        printSecond.run();
        seam_two_second.release();
       

    }

    public void third(Runnable printThird) throws InterruptedException {
      seam_two_second.acquire();
        printThird.run();
    }
}

1115. 交替打印FooBar

class FooBar {
    private int n;
    private volatile int flag=-1;
    public FooBar(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        
        for (int i = 0; i < n; i++) {
            while(flag!=-1){
                //当前线程让步,否则超时
                Thread.yield();
            }
        	// printFoo.run() outputs "foo". Do not change or remove this line.
        	printFoo.run();
             flag=1;
        }
       
    }

    public void bar(Runnable printBar) throws InterruptedException {
      
        for (int i = 0; i < n; i++) {
              while(flag!=1){
                     //当前线程让步,否则超时
                Thread.yield();
            }
            // printBar.run() outputs "bar". Do not change or remove this line.
        	printBar.run();
            flag=-1;
        }
     
    }
}

1116. 打印零与奇偶数

class ZeroEvenOdd {
    private int n;
    private volatile int flag=0;
    private volatile int count=1;
    public ZeroEvenOdd(int n) {
        this.n = n;
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void zero(IntConsumer printNumber) throws InterruptedException {
        
         for(int i=0;i<n;i++){
        while(flag!=0){
            Thread.yield();
        }
        printNumber.accept(0);
        if(count%2==0)
        flag=2;
        else 
        flag=1;
         }
    }

    public void even(IntConsumer printNumber) throws InterruptedException {
     for(int i=2;i<=n;i+=2){
          while(flag!=2){
              Thread.yield();
          }
          printNumber.accept(count++);
          flag=0;
     }
    }

    public void odd(IntConsumer printNumber) throws InterruptedException {
          for(int i=1;i<=n;i+=2){
         while(flag!=1){
             Thread.yield();
         }
         printNumber.accept(count++);
         flag=0;
           }
    }
}

1117. H2O 生成

class H2O {
    private Semaphore semaphoreH=new Semaphore(2);
    private Semaphore semaphoreO=new Semaphore(1);
    
    
    private CyclicBarrier cyclicBarrier=new CyclicBarrier(3);
    public H2O() {

    }

    public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
        semaphoreH.acquire();
        try {
            cyclicBarrier.await();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        // releaseHydrogen.run() outputs "H". Do not change or remove this line.
        releaseHydrogen.run();
        semaphoreH.release();
    }

    public void oxygen(Runnable releaseOxygen) throws InterruptedException {
        semaphoreO.acquire();
        try {
            cyclicBarrier.await();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        // releaseOxygen.run() outputs "O". Do not change or remove this line.
        releaseOxygen.run();
        semaphoreO.release();
    }
}

1195. 交替打印字符串

class FizzBuzz {
    private volatile int count=1;
    private volatile int flag=4;
    private int n;

    public FizzBuzz(int n) {
        this.n = n;
    }
    public void setFlag(int count){
        if(count%3==0&&count%5==0)
            flag=3;
        else if(count%3==0)
            flag=1;
        else if(count%5==0)
            flag=2;
        else
            flag=4;
    }
    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
        while (count<=n){

            while (flag!=1){
                if(count>n) 
                break;
                Thread.yield();
            }  
               if(count>n) 
                break;
         
            printFizz.run();
            
            setFlag(++count);
              
        }
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        while (count<=n){
            while (flag!=2){
               

                 if(count>n) 
                break;   
                Thread.yield();
            }
               if(count>n) 
                break;
          
            printBuzz.run();
              
            setFlag(++count);
            
        }
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        while (count<=n){


            while (flag!=3){
                 if(count>n) 
                break;   
                Thread.yield();
            }
               if(count>n) 
                break;
           
            printFizzBuzz.run();
            setFlag(++count); 
            
        }
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
        while (count<=n){
                 //其他线程并发修改导致n>16
                //比如这个线程进入的时候n=15,
                //另一个线程也是n=15
                //这个线程让步,其他线程+1导致n=16
                //n=16,其他线程不再进去
                //while循环或者也是在自旋中,进入死锁
                //flag没有人帮他修改,一直自旋。
            while (flag!=4){
                if(count>n) 
                break;    
                Thread.yield();
            }
               if(count>n) 
                break;
             
              printNumber.accept(count);
              setFlag(++count);
               
        }
    }
}

1226. 哲学家进餐

解法1:

class DiningPhilosophers {
    //叉子是有顺序的,所以不能用信号量来表示,比如0号哲学家只能拿左右的叉子
    //5把叉子对应五把锁,表示互斥变量 不可同时进入
    private final ReentrantLock[] fork = {new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock()};


    //同时最多有4个人拿起叉子,就不会造成死锁
    private Semaphore eatNumber = new Semaphore(4);

    public DiningPhilosophers() {

    }

    // call the run() method of any runnable to execute its code
    public void wantsToEat(int philosopher,
                           Runnable pickLeftFork,
                           Runnable pickRightFork,
                           Runnable eat,
                           Runnable putLeftFork,
                           Runnable putRightFork) throws InterruptedException {
        //左右叉子编号
        int leftFork = (philosopher + 1) % 5;
        int rightFork = philosopher;

        //申请拿叉子
        eatNumber.acquire();
        //叉子上锁
        fork[leftFork].lock();
        fork[rightFork].lock();
        
        //线程具体实现
        pickLeftFork.run();
        pickRightFork.run();
        eat.run();
        putLeftFork.run();
        putRightFork.run();

        //开锁
        fork[leftFork].unlock();
        fork[rightFork].unlock();
        
        //释放
        eatNumber.release();
    }
}

方法二:

class DiningPhilosophers {
    

    //保证每次只有一个人吃 
    //(改进:可以每次两个人吃,也就是第一种做法,需要对叉子加锁)
    private Semaphore eatNumber = new Semaphore(1);

    public DiningPhilosophers() {

    }

    // call the run() method of any runnable to execute its code
    public void wantsToEat(int philosopher,
                           Runnable pickLeftFork,
                           Runnable pickRightFork,
                           Runnable eat,
                           Runnable putLeftFork,
                           Runnable putRightFork) throws InterruptedException {
      

        //申请拿叉子
        eatNumber.acquire();
   
       

        //线程具体实现
        pickLeftFork.run();
        pickRightFork.run();
        eat.run();
        putLeftFork.run();
        putRightFork.run();

           

        //释放
        eatNumber.release();
    }
}

解法3:

class DiningPhilosophers {
    //1个Fork视为1个ReentrantLock,5个叉子即5个ReentrantLock,将其都放入数组中
    private final ReentrantLock[] lockList = {new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock()};

    public DiningPhilosophers() {

    }

    // call the run() method of any runnable to execute its code
    public void wantsToEat(int philosopher,
                           Runnable pickLeftFork,
                           Runnable pickRightFork,
                           Runnable eat,
                           Runnable putLeftFork,
                           Runnable putRightFork) throws InterruptedException {

        int leftFork = (philosopher + 1) % 5;    //左边的叉子 的编号
        int rightFork = philosopher;    //右边的叉子 的编号

        //编号为偶数的哲学家,优先拿起左边的叉子,再拿起右边的叉子
        if (philosopher % 2 == 0) {
            lockList[leftFork].lock();    //拿起左边的叉子
            lockList[rightFork].lock();    //拿起右边的叉子
        }
        //编号为奇数的哲学家,优先拿起右边的叉子,再拿起左边的叉子
        else {
            lockList[rightFork].lock();    //拿起右边的叉子
            lockList[leftFork].lock();    //拿起左边的叉子
        }

        pickLeftFork.run();    //拿起左边的叉子 的具体执行
        pickRightFork.run();    //拿起右边的叉子 的具体执行

        eat.run();    //吃意大利面 的具体执行

        putLeftFork.run();    //放下左边的叉子 的具体执行
        putRightFork.run();    //放下右边的叉子 的具体执行

        lockList[leftFork].unlock();    //放下左边的叉子
        lockList[rightFork].unlock();    //放下右边的叉子
    }
}

方法4:

class DiningPhilosophers {
    //0表示没人使用,1表示有人使用 

    //错误解法,volatile保证可见性,两个线程可能同时读到forkState等于0,但是提交通过了???,严谨一点应该通过AtomicInteger设置具体状态
    private volatile int[] forkState=new int[5];
   

    public DiningPhilosophers() {

    }

    // call the run() method of any runnable to execute its code
    public void wantsToEat(int philosopher,
                           Runnable pickLeftFork,
                           Runnable pickRightFork,
                           Runnable eat,
                           Runnable putLeftFork,
                           Runnable putRightFork) throws InterruptedException {

        int leftFork = (philosopher + 1) % 5;    //左边的叉子 的编号
        int rightFork = philosopher;    //右边的叉子 的编号

        //编号为偶数的哲学家,优先拿起左边的叉子,再拿起右边的叉子
        if (philosopher % 2 == 0) {
            while (forkState[leftFork]==1){
                Thread.sleep(1);
            }
                forkState[leftFork]=1;
            while (forkState[rightFork]==1){
                Thread.sleep(1);
            }
                forkState[rightFork]=1;
        }
        //编号为奇数的哲学家,优先拿起右边的叉子,再拿起左边的叉子
        else {
             while (forkState[leftFork]==1){
                Thread.sleep(1);
            }
            forkState[leftFork]=1;
            while (forkState[rightFork]==1){
                Thread.sleep(1);
            }
            forkState[rightFork]=1;
           
           

        }

        pickLeftFork.run();    //拿起左边的叉子 的具体执行
        pickRightFork.run();    //拿起右边的叉子 的具体执行

        eat.run();    //吃意大利面 的具体执行

        putLeftFork.run();    //放下左边的叉子 的具体执行
        putRightFork.run();    //放下右边的叉子 的具体执行
        forkState[rightFork]=0;
        forkState[leftFork]=0;
    }
}

解法的详细解释对应:https://leetcode-cn.com/problems/the-dining-philosophers/solution/1ge-semaphore-1ge-reentrantlockshu-zu-by-gfu/,方法1,2,3、4分别对应文中123

猜你喜欢

转载自blog.csdn.net/weixin_44137260/article/details/106058490