LeetCode多线程

1114. 按序打印
    我们提供了一个类:

    public class Foo {
      public void one() { print("one"); }
      public void two() { print("two"); }
      public void three() { print("three"); }
    }
    三个不同的线程将会共用一个 Foo 实例。

    线程 A 将会调用 one() 方法
    线程 B 将会调用 two() 方法
    线程 C 将会调用 three() 方法
    请设计修改程序,以确保 two() 方法在 one() 方法之后被执行,three() 方法在 two() 方法之后被执行。
    
    解法一:Synchronized锁和控制变量
    //控制变量
    private int flag = 0;
    //定义object 对象为锁
    private Object lock = new Object();

    public FooMethodTwo()
    {

    }
    public void first (Runnable printFirst) throws  InterruptedException
    {
        synchronized (lock)
        {
            //如果falg 不为0 则让first 线程等待,while 循环控制first 线程 如果不满足条件
            while (flag != 0)
            {
                lock.wait();
            }
            printFirst.run();
            flag = 1;
            //唤醒其余所有的线程
            lock.notifyAll();
        }
    }

    public void second(Runnable printSecond) throws InterruptedException
    {
        synchronized (lock)
        {
            //如果成员变量不为1 则让二号等待
            while (flag != 1)
            {
                lock.wait();
            }
            printSecond.run();
            flag = 2;
            //唤醒其余所有的线程
            lock.notifyAll();

        }
    }
    public void third(Runnable printThird) throws InterruptedException
    {
        synchronized (lock)
        {
            //如果成员变量不为2 则一直处于等待的状态
            while (flag != 2)
            {
                lock.wait();
            }
            printThird.run();
            flag = 0;
            //唤醒其余所有的线程
            lock.notifyAll();

        }
    }
    public static void main(String[] args)
    {
        FooMethodTwo foo = new FooMethodTwo();

        Thread thread1 = new Thread();
        try
        {
            foo.first(() ->
            {
                System.out.println("1");
            });
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        };

        Thread thread2 = new Thread();
        try
        {
            foo.second(() ->

                    System.out.println("2")

            );
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        Thread thread3 = new Thread();
        try
        {
            foo.third(() -> {
                System.out.println("3");
            });
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        thread1.start();
        thread2.start();
        thread3.start();
    }
    
    
    
    解法二:CountDownLatch
    
 //声明两个CountDownLatch 变量
    private CountDownLatch second;
    private CountDownLatch third;
    public FooMethodOne() {
        //初始化每个CountDownLatch的值为1,表示有一个线程执行完后,执行等待的线程
        second = new CountDownLatch(1);
        third = new CountDownLatch(1);
    }

    public void first(Runnable printFirst) throws InterruptedException {
        //当前只有first线程没有任何的阻碍,其余两个线程都处于等待阶段
        //直到second里面计数为0才执行因调用该second.await()而等待的线程
        printFirst.run();
        second.countDown();
    }

    public void second(Runnable printSecond) throws InterruptedException {
        //只有second 为0 才能通过,否则会一直阻塞
        second.await();
        printSecond.run();
        //直到third 里面计数为0才执行因为调用该 third.await()而等待的线程
        third.countDown();
    }

    public void third(Runnable printThird) throws InterruptedException {

        //只有third 为0 才通过 否则一直阻塞
        third.await();
        printThird.run();
    }


    public static void main(String[] args)
    {
        FooMethodOne foo = new FooMethodOne();

        Thread thread1 = new Thread();
        try
        {
            foo.first(() ->
            {
                System.out.println("one");
            });
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        };

        Thread thread2 = new Thread();
        try
        {
            foo.second(() ->

                System.out.println("two")

            );
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        Thread thread3 = new Thread();
        try
        {
            foo.third(() -> {
                System.out.println("three");
            });
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        thread1.start();
        thread2.start();
        thread3.start();
    }
    
    解法三:Semaphore(信号量)
    Semaphore与CountDownLatch相似,不同的地方在于Semaphore的值被获取到后是可以释放的,并不像CountDownLatch那样一直减到底

    获得Semaphore的线程处理完它的逻辑之后,你就可以调用它的Release()函数将它的计数器重新加1,这样其它被阻塞的线程就可以得到调用了

    //控制变量
    private int flag = 0;
    //定义object 对象为锁
    private Object lock = new Object();

    public FooMethodTwo()
    {

    }
    public void first (Runnable printFirst) throws  InterruptedException
    {
        synchronized (lock)
        {
            //如果falg 不为0 则让first 线程等待,while 循环控制first 线程 如果不满足条件
            while (flag != 0)
            {
                lock.wait();
            }
            printFirst.run();
            flag = 1;
            //唤醒其余所有的线程
            lock.notifyAll();
        }
    }

    public void second(Runnable printSecond) throws InterruptedException
    {
        synchronized (lock)
        {
            //如果成员变量不为1 则让二号等待
            while (flag != 1)
            {
                lock.wait();
            }
            printSecond.run();
            flag = 2;
            //唤醒其余所有的线程
            lock.notifyAll();

        }
    }
    public void third(Runnable printThird) throws InterruptedException
    {
        synchronized (lock)
        {
            //如果成员变量不为2 则一直处于等待的状态
            while (flag != 2)
            {
                lock.wait();
            }
            printThird.run();
            flag = 0;
            //唤醒其余所有的线程
            lock.notifyAll();

        }
    }
    public static void main(String[] args)
    {
        FooMethodTwo foo = new FooMethodTwo();

        Thread thread1 = new Thread();
        try
        {
            foo.first(() ->
            {
                System.out.println("1");
            });
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        };

        Thread thread2 = new Thread();
        try
        {
            foo.second(() ->

                    System.out.println("2")

            );
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        Thread thread3 = new Thread();
        try
        {
            foo.third(() -> {
                System.out.println("3");
            });
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        thread1.start();
        thread2.start();
        thread3.start();
    }


    
1115. 交替打印FooBar
        我们提供一个类:

    class FooBar {
      public void foo() {
        for (int i = 0; i < n; i++) {
          print("foo");
        }
      }

      public void bar() {
        for (int i = 0; i < n; i++) {
          print("bar");
        }
      }
    }
    两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。

    请设计修改程序,以确保 "foobar" 被输出 n 次。

     解法一、生产消费者模型
    
    
    
    
    
    解法二、Semaphore
    private int n;
    public static void main(String[] args)
    {
        FooBarMethod01 fb = new FooBarMethod01(6);

        //写法一
        new Thread(){
            @Override
            public void run()
            {
                try
                {
                    fb.foo(() -> System.out.print("foo"));
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }.start();
        //写法二
        Thread thread2 = new Thread();
        thread2.run();
        try
        {
            fb.bar(() -> System.out.print("bar\n"));
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        thread2.start();
    }

    public  FooBarMethod01(int n)
    {
        this.n = n;
    }

    Semaphore foo = new Semaphore(1);
    Semaphore bar = new Semaphore(0);

    public  void foo(Runnable printFoo) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            foo.acquire();
            printFoo.run();
            bar.release();
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            bar.acquire();
            printBar.run();
            foo.release();
        }
    }
    
    
    
    
    
知识点:
    Java的concurrent包里面的CountDownLatch其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。

      你可以向CountDownLatch对象设置一个初始的数字作为计数值,任何调用这个对象上的await()方法都会阻塞,直到这个计数器的计数值被其他的线程减为0为止。

      CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。

 

所有材料及题解来源均出于:力扣(LeetCode)
链接:https://leetcode-cn.com/problems
申明:著作权归领扣网络所有,商业转载请联系官方授权。
      
      
      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值