精华内容
下载资源
问答
  • 2021-06-03 17:28:35

    join

    thread.join();使主线程等待thread执行完毕。

    单线程池

    使用Executors.newSingleThreadExecutor(),创建单线城池,然后顺序提交任务以保证线程的顺序执行。

    volatile

    使用volatile关键字,使共享变量可见。通过判断变量的值,配合thread.wait()/notify()/notifyAll(),达到控制线程顺序的目的。

    Condition

    使用ReentrantLock的 Condition condition = lock.newCondition();condition.await()/singal();

    更多相关内容
  • 主要介绍了java多线程如何指定顺序同步执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 本文使用了7中方法实现在多线程中让线程按顺序运行的方法,涉及到多线程中许多常用的方法,不止为了知道如何让线程按顺序运行,更是让读者对多线程的使用有更深刻的了解。 使用的方法如下: [1] 使用线程的join方法 ...

    转自:https://www.cnblogs.com/wenjunwei/p/10573289.html

    一.前言
    本文使用了7中方法实现在多线程中让线程按顺序运行的方法,涉及到多线程中许多常用的方法,不止为了知道如何让线程按顺序运行,更是让读者对多线程的使用有更深刻的了解。 使用的方法如下:

    [1] 使用线程的join方法
    [2] 使用主线程的join方法
    [3] 使用线程的wait方法
    [4] 使用线程的线程池方法
    [5] 使用线程的Condition(条件变量)方法
    [6] 使用线程的CountDownLatch(倒计数)方法
    [7] 使用线程的CyclicBarrier(回环栅栏)方法
    [8] 使用线程的Semaphore(信号量)方法
    二.实现
    我们下面需要完成这样一个应用场景:

    1.早上;2.测试人员、产品经理、开发人员陆续的来公司上班;3.产品经理规划新需求;4.开发人员开发新需求功能;5.测试人员测试新功能。

    规划需求,开发需求新功能,测试新功能是一个有顺序的,我们把thread1看做产品经理,thread2看做开发人员,thread3看做测试人员。

    1.使用线程的join方法
    join():是Theard的方法,作用是调用线程需等待该join()线程执行完成后,才能继续用下运行。

    应用场景:当一个线程必须等待另一个线程执行完毕才能执行时可以使用join方法。

    package com.wwj.javabase.thread.order;

    /**

    • @author wwj

    • 通过子程序join使线程按顺序执行
      */
      public class ThreadJoinDemo {

      public static void main(String[] args) {
      final Thread thread1 = new Thread(new Runnable() {
      @Override
      public void run() {
      System.out.println(“产品经理规划新需求”);
      }
      });

       final Thread thread2 = new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   thread1.join();
                   System.out.println("开发人员开发新需求功能");
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       });
      
       Thread thread3 = new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   thread2.join();
                   System.out.println("测试人员测试新功能");
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       });
      
       System.out.println("早上:");
       System.out.println("测试人员来上班了...");
       thread3.start();
       System.out.println("产品经理来上班了...");
       thread1.start();
       System.out.println("开发人员来上班了...");
       thread2.start();
      

      }
      }
      运行结果

    早上:
    测试人员来上班了…
    产品经理来上班了…
    开发人员来上班了…
    产品经理规划新需求
    开发人员开发新需求功能
    测试人员测试新功能
    2.使用主线程的join方法
    这里是在主线程中使用join()来实现对线程的阻塞。

    package com.wwj.javabase.thread.order;

    /**

    • @author wwj

    • 通过主程序join使线程按顺序执行
      */
      public class ThreadMainJoinDemo {

      public static void main(String[] args) throws Exception {

       final Thread thread1 = new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("产品经理正在规划新需求...");
           }
       });
      
       final Thread thread2 = new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("开发人员开发新需求功能");
           }
       });
      
       final Thread thread3 = new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("测试人员测试新功能");
           }
       });
      
       System.out.println("早上:");
       System.out.println("产品经理来上班了");
       System.out.println("测试人员来上班了");
       System.out.println("开发人员来上班了");
       thread1.start();
       //在父进程调用子进程的join()方法后,父进程需要等待子进程运行完再继续运行。
       System.out.println("开发人员和测试人员休息会...");
       thread1.join();
       System.out.println("产品经理新需求规划完成!");
       thread2.start();
       System.out.println("测试人员休息会...");
       thread2.join();
       thread3.start();
      

      }
      }
      运行结果

    产品经理来上班了
    测试人员来上班了
    开发人员来上班了
    开发人员和测试人员休息会…
    产品经理正在规划新需求…
    产品经理新需求规划完成!
    测试人员休息会…
    开发人员开发新需求功能
    测试人员测试新功能
    3.使用线程的wait方法
    wait():是Object的方法,作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)

    notify()和notifyAll():是Object的方法,作用则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。

    wait(long timeout):让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的notify()方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。

    应用场景:Java实现生产者消费者的方式。

    package com.wwj.javabase.thread.order;

    /**

    • @author wwj
      */
      public class ThreadWaitDemo {

      private static Object myLock1 = new Object();
      private static Object myLock2 = new Object();

      /**

      • 为什么要加这两个标识状态?

      • 如果没有状态标识,当t1已经运行完了t2才运行,t2在等待t1唤醒导致t2永远处于等待状态
        */
        private static Boolean t1Run = false;
        private static Boolean t2Run = false;
        public static void main(String[] args) {

        final Thread thread1 = new Thread(new Runnable() {
        @Override
        public void run() {
        synchronized (myLock1){
        System.out.println(“产品经理规划新需求…”);
        t1Run = true;
        myLock1.notify();
        }
        }
        });

        final Thread thread2 = new Thread(new Runnable() {
        @Override
        public void run() {
        synchronized (myLock1){
        try {
        if(!t1Run){
        System.out.println(“开发人员先休息会…”);
        myLock1.wait();
        }
        synchronized (myLock2){
        System.out.println(“开发人员开发新需求功能”);
        myLock2.notify();
        }
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        }
        }
        });

        Thread thread3 = new Thread(new Runnable() {
        @Override
        public void run() {
        synchronized (myLock2){
        try {
        if(!t2Run){
        System.out.println(“测试人员先休息会…”);
        myLock2.wait();
        }
        System.out.println(“测试人员测试新功能”);
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        }
        }
        });

        System.out.println(“早上:”);
        System.out.println(“测试人员来上班了…”);
        thread3.start();
        System.out.println(“产品经理来上班了…”);
        thread1.start();
        System.out.println(“开发人员来上班了…”);
        thread2.start();
        }
        }
        运行结果:这里输出会有很多种顺序,主要是因为线程进入的顺序,造成锁住线程的顺序不一致。

    早上:
    测试人员来上班了…
    产品经理来上班了…
    开发人员来上班了…
    测试人员先休息会…
    产品经理规划新需求…
    开发人员开发新需求功能
    测试人员测试新功能
    4.使用线程的线程池方法
    JAVA通过Executors提供了四种线程池

    单线程化线程池(newSingleThreadExecutor);
    可控最大并发数线程池(newFixedThreadPool);
    可回收缓存线程池(newCachedThreadPool);
    支持定时与周期性任务的线程池(newScheduledThreadPool)。
    单线程化线程池(newSingleThreadExecutor):优点,串行执行所有任务。

    submit():提交任务。

    shutdown():方法用来关闭线程池,拒绝新任务。

    应用场景:串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

    package com.wwj.javabase.thread.order;

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    /**

    • @author wwj

    • 通过SingleThreadExecutor让线程按顺序执行
      */
      public class ThreadPoolDemo {

      static ExecutorService executorService = Executors.newSingleThreadExecutor();

      public static void main(String[] args) throws Exception {

       final Thread thread1 = new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("产品经理规划新需求");
           }
       });
      
       final Thread thread2 = new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("开发人员开发新需求功能");
           }
       });
      
       Thread thread3 = new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("测试人员测试新功能");
           }
       });
      
       System.out.println("早上:");
       System.out.println("产品经理来上班了");
       System.out.println("测试人员来上班了");
       System.out.println("开发人员来上班了");
       System.out.println("领导吩咐:");
       System.out.println("首先,产品经理规划新需求...");
       executorService.submit(thread1);
       System.out.println("然后,开发人员开发新需求功能...");
       executorService.submit(thread2);
       System.out.println("最后,测试人员测试新功能...");
       executorService.submit(thread3);
       executorService.shutdown();
      

      }
      }
      运行结果

    早上:
    产品经理来上班了
    测试人员来上班了
    开发人员来上班了
    领导吩咐:
    首先,产品经理规划新需求…
    然后,开发人员开发新需求功能…
    最后,测试人员测试新功能…
    产品经理规划新需求
    开发人员开发新需求功能
    测试人员测试新功能
    5.使用线程的Condition(条件变量)方法
    Condition(条件变量):通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。

    Condition中await()方法类似于Object类中的wait()方法。

    Condition中await(long time,TimeUnit unit)方法类似于Object类中的wait(long time)方法。

    Condition中signal()方法类似于Object类中的notify()方法。

    Condition中signalAll()方法类似于Object类中的notifyAll()方法。

    应用场景:Condition是一个多线程间协调通信的工具类,使得某个,或者某些线程一起等待某个条件(Condition),只有当该条件具备( signal 或者 signalAll方法被带调用)时 ,这些等待线程才会被唤醒,从而重新争夺锁。

    package com.wwj.javabase.thread.order;

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;

    /**

    • @author wwj

    • 使用Condition(条件变量)实现线程按顺序运行
      */
      public class ThreadConditionDemo {

      private static Lock lock = new ReentrantLock();
      private static Condition condition1 = lock.newCondition();
      private static Condition condition2 = lock.newCondition();

      /**

      • 为什么要加这两个标识状态?
      • 如果没有状态标识,当t1已经运行完了t2才运行,t2在等待t1唤醒导致t2永远处于等待状态
        */
        private static Boolean t1Run = false;
        private static Boolean t2Run = false;

      public static void main(String[] args) {

       final Thread thread1 = new Thread(new Runnable() {
           @Override
           public void run() {
               lock.lock();
               System.out.println("产品经理规划新需求");
               t1Run = true;
               condition1.signal();
               lock.unlock();
           }
       });
      
       final Thread thread2 = new Thread(new Runnable() {
           @Override
           public void run() {
               lock.lock();
               try {
                   if(!t1Run){
                       System.out.println("开发人员先休息会...");
                       condition1.await();
                   }
                   System.out.println("开发人员开发新需求功能");
                   t2Run = true;
                   condition2.signal();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               lock.unlock();
           }
       });
      
       Thread thread3 = new Thread(new Runnable() {
           @Override
           public void run() {
               lock.lock();
               try {
                   if(!t2Run){
                       System.out.println("测试人员先休息会...");
                       condition2.await();
                   }
                   System.out.println("测试人员测试新功能");
                   lock.unlock();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       });
      
       System.out.println("早上:");
       System.out.println("测试人员来上班了...");
       thread3.start();
       System.out.println("产品经理来上班了...");
       thread1.start();
       System.out.println("开发人员来上班了...");
       thread2.start();
      

      }
      }
      运行结果:这里输出会有很多种顺序,主要是因为线程进入的顺序,造成锁住线程的顺序不一致

    早上:
    测试人员来上班了…
    产品经理来上班了…
    开发人员来上班了…
    测试人员先休息会…
    产品经理规划新需求
    开发人员开发新需求功能
    测试人员测试新功能
    6.使用线程的CountDownLatch(倒计数)方法
    CountDownLatch:位于java.util.concurrent包下,利用它可以实现类似计数器的功能。

    应用场景:比如有一个任务C,它要等待其他任务A,B执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。

    package com.wwj.javabase.thread.order;

    import java.util.concurrent.CountDownLatch;

    /**

    • @author wwj

    • 通过CountDownLatch(倒计数)使线程按顺序执行
      */
      public class ThreadCountDownLatchDemo {

      /**

      • 用于判断线程一是否执行,倒计时设置为1,执行后减1
        */
        private static CountDownLatch c1 = new CountDownLatch(1);

      /**

      • 用于判断线程二是否执行,倒计时设置为1,执行后减1
        */
        private static CountDownLatch c2 = new CountDownLatch(1);

      public static void main(String[] args) {
      final Thread thread1 = new Thread(new Runnable() {
      @Override
      public void run() {
      System.out.println(“产品经理规划新需求”);
      //对c1倒计时-1
      c1.countDown();
      }
      });

       final Thread thread2 = new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   //等待c1倒计时,计时为0则往下运行
                   c1.await();
                   System.out.println("开发人员开发新需求功能");
                   //对c2倒计时-1
                   c2.countDown();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       });
      
       Thread thread3 = new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   //等待c2倒计时,计时为0则往下运行
                   c2.await();
                   System.out.println("测试人员测试新功能");
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       });
      
       System.out.println("早上:");
       System.out.println("测试人员来上班了...");
       thread3.start();
       System.out.println("产品经理来上班了...");
       thread1.start();
       System.out.println("开发人员来上班了...");
       thread2.start();
      

      }
      }
      运行结果

    早上:
    测试人员来上班了…
    产品经理来上班了…
    开发人员来上班了…
    产品经理规划新需求
    开发人员开发新需求功能
    测试人员测试新功能
    7.使用CyclicBarrier(回环栅栏)实现线程按顺序运行
    CyclicBarrier(回环栅栏):通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。

    应用场景:公司组织春游,等待所有的员工到达集合地点才能出发,每个人到达后进入barrier状态。都到达后,唤起大家一起出发去旅行。

    package com.wwj.javabase.thread.order;

    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;

    /**

    • @author wwj

    • 使用CyclicBarrier(回环栅栏)实现线程按顺序运行
      */
      public class CyclicBarrierDemo {

      static CyclicBarrier barrier1 = new CyclicBarrier(2);
      static CyclicBarrier barrier2 = new CyclicBarrier(2);

      public static void main(String[] args) {

       final Thread thread1 = new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   System.out.println("产品经理规划新需求");
                   //放开栅栏1
                   barrier1.await();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               } catch (BrokenBarrierException e) {
                   e.printStackTrace();
               }
           }
       });
      
       final Thread thread2 = new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   //放开栅栏1
                   barrier1.await();
                   System.out.println("开发人员开发新需求功能");
                   //放开栅栏2
                   barrier2.await();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               } catch (BrokenBarrierException e) {
                   e.printStackTrace();
               }
           }
       });
      
       final Thread thread3 = new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   //放开栅栏2
                   barrier2.await();
                   System.out.println("测试人员测试新功能");
               } catch (InterruptedException e) {
                   e.printStackTrace();
               } catch (BrokenBarrierException e) {
                   e.printStackTrace();
               }
           }
       });
      
       System.out.println("早上:");
       System.out.println("测试人员来上班了...");
       thread3.start();
       System.out.println("产品经理来上班了...");
       thread1.start();
       System.out.println("开发人员来上班了...");
       thread2.start();
      

      }
      }
      运行结果

    早上:
    测试人员来上班了…
    产品经理来上班了…
    开发人员来上班了…
    产品经理规划新需求
    开发人员开发新需求功能
    测试人员测试新功能
    8.使用Sephmore(信号量)实现线程按顺序运行
    Sephmore(信号量):Semaphore是一个计数信号量,从概念上将,Semaphore包含一组许可证,如果有需要的话,每个acquire()方法都会阻塞,直到获取一个可用的许可证,每个release()方法都会释放持有许可证的线程,并且归还Semaphore一个可用的许可证。然而,实际上并没有真实的许可证对象供线程使用,Semaphore只是对可用的数量进行管理维护。

    acquire():当前线程尝试去阻塞的获取1个许可证,此过程是阻塞的,当前线程获取了1个可用的许可证,则会停止等待,继续执行。

    release():当前线程释放1个可用的许可证。

    应用场景:Semaphore可以用来做流量分流,特别是对公共资源有限的场景,比如数据库连接。假设有这个的需求,读取几万个文件的数据到数据库中,由于文件读取是IO密集型任务,可以启动几十个线程并发读取,但是数据库连接数只有10个,这时就必须控制最多只有10个线程能够拿到数据库连接进行操作。这个时候,就可以使用Semaphore做流量控制。

    package com.wwj.javabase.thread.order;

    import java.util.concurrent.Semaphore;
    /**

    • @author wwj

    • 使用Sephmore(信号量)实现线程按顺序运行
      */
      public class SemaphoreDemo {
      private static Semaphore semaphore1 = new Semaphore(1);
      private static Semaphore semaphore2 = new Semaphore(1);
      public static void main(String[] args) {
      final Thread thread1 = new Thread(new Runnable() {
      @Override
      public void run() {
      System.out.println(“产品经理规划新需求”);
      semaphore1.release();
      }
      });

       final Thread thread2 = new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   semaphore1.acquire();
                   System.out.println("开发人员开发新需求功能");
                   semaphore2.release();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       });
      
       Thread thread3 = new Thread(new Runnable() {
           @Override
           public void run() {
               try {
                   semaphore2.acquire();
                   thread2.join();
                   semaphore2.release();
                   System.out.println("测试人员测试新功能");
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       });
      
       System.out.println("早上:");
       System.out.println("测试人员来上班了...");
       thread3.start();
       System.out.println("产品经理来上班了...");
       thread1.start();
       System.out.println("开发人员来上班了...");
       thread2.start();
      

      }
      }
      运行结果

    早上:
    测试人员来上班了…
    产品经理来上班了…
    开发人员来上班了…
    产品经理规划新需求
    开发人员开发新需求功能
    测试人员测试新功能
    总结
    看完了这么多种方法,是不是对多线程有了更深入的了解呢?不妨自己试试吧(代码拷贝均可运行)

    使用的场景还有很多,根据开发需求场景,选择合适的方法,达到事半功倍的效果。

    留了个坑
    看了评论发现,有时候确实没有按顺序运行,这是为什么?

    解答:按顺序运行的条件是所有线程都处于运行状态,而这里三个线程并不能保证同时进入了运行状态,我们可以使用CountDownLatch让三个线程都进入运行状态后再执行业务代码,这样就不会出现没有按顺序运行的情况了。

    展开全文
  • 主要介绍了浅谈Python3多线程之间的执行顺序问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 我们提供了一个类: public class Foo { ...三个不同的线程 A、B、C 将会共用一个 Foo 实例。 一个将会调用 first() 方法 一个将会调用 second() 方法 还有一个将会调用 third() 方法 请设计修改程序,以

    我们提供了一个类:

    public class Foo {
      public void first() { print("first"); }
      public void second() { print("second"); }
      public void third() { print("third"); }
    }
    

    三个不同的线程 A、B、C 将会共用一个 Foo 实例。

    一个将会调用 first() 方法
    一个将会调用 second() 方法
    还有一个将会调用 third() 方法
    请设计修改程序,以确保 second() 方法在 first() 方法之后被执行,third() 方法在 second() 方法之后被执行。

    法一:信号量

    #include <semaphore.h>
    class Foo {
    private:
        sem_t firstDone;
        sem_t secondDone;
    public:
        Foo() {
            sem_init(&firstDone,0,0);
            sem_init(&secondDone,0,0);
        }
    
        void first(function<void()> printFirst) {
            
            // printFirst() outputs "first". Do not change or remove this line.
            printFirst();
            sem_post(&firstDone);
        }
    
        void second(function<void()> printSecond) {
            sem_wait(&firstDone);
            // printSecond() outputs "second". Do not change or remove this line.
            printSecond();
            sem_post(&secondDone);
        }
    
        void third(function<void()> printThird) {
            sem_wait(&secondDone);
            // printThird() outputs "third". Do not change or remove this line.
            printThird();
        }
    };
    

    互斥锁:mutex

    #include <semaphore.h>
    class Foo {
    private:
        mutex mtx1;
        mutex mtx2;
    public:
        Foo() {
            mtx1.lock();
            mtx2.lock();
        }
    
        void first(function<void()> printFirst) {
            
            // printFirst() outputs "first". Do not change or remove this line.
            printFirst();
            mtx1.unlock();
        }
    
        void second(function<void()> printSecond) {
            mtx1.lock();
            // printSecond() outputs "second". Do not change or remove this line.
            printSecond();
            mtx1.unlock();
            mtx2.unlock();
        }
    
        void third(function<void()> printThird) {
            mtx2.lock();
            // printThird() outputs "third". Do not change or remove this line.
            printThird();
            mtx2.unlock();
        }
    };
    

    RAII lock_guard, unique_lock

    #include <semaphore.h>
    class Foo {
    private:
        mutex mtx1;
        mutex mtx2;
        unique_lock<mutex> m1lock,m2lock;
    public:
        Foo() :m1lock(mtx1,try_to_lock),m2lock(mtx2,try_to_lock){
            
        }
    
        void first(function<void()> printFirst) {
            
            // printFirst() outputs "first". Do not change or remove this line.
            printFirst();
            m1lock.unlock();
        }
    
        void second(function<void()> printSecond) {
            lock_guard<mutex> guard(mtx1);
            // printSecond() outputs "second". Do not change or remove this line.
            printSecond();
            m2lock.unlock();
        }
    
        void third(function<void()> printThird) {
            lock_guard<mutex> guard(mtx2);
            // printThird() outputs "third". Do not change or remove this line.
            printThird();
        }
    };
    

    条件变量

    #include <semaphore.h>
    class Foo {
    private:
        condition_variable cv;
        mutex mtx;
        int k;
    public:
        Foo() {
            k = 0;
        }
    
        void first(function<void()> printFirst) {
            printFirst();
            k = 1;
            cv.notify_all();
        }
    
        void second(function<void()> printSecond) {
            unique_lock<mutex> lock(mtx);
            cv.wait(lock,[this](){return k==1;});
            printSecond();
            k=2;
            cv.notify_one();
        }
    
        void third(function<void()> printThird) {
            unique_lock<mutex> lock(mtx);
            cv.wait(lock,[this](){return k==2;});
            printThird();
        }
    };
    

    原子操作

    异步操作

    class Foo {
        promise<void> pro1,pro2;
    public:
        Foo() {
            
        }
    
        void first(function<void()> printFirst) {
            printFirst();
            pro1.set_value();
        }
    
        void second(function<void()> printSecond) {
            pro1.get_future().wait();
            printSecond();
            pro2.set_value();
        }
    
        void third(function<void()> printThird) {
            pro2.get_future().wait();
            printThird();
        }
    };
    
    展开全文
  • 题目要求:创建三个线程,每个线程分别打印ABC,并按照ABC的顺序执行十次 题目可以使用多种不同的方式解决,下面我们分别使用 Condition 等待唤醒机制、Semaphore 信号量、CountDownLatch 闭锁、Thread.join() 方法...

    题目要求:创建三个线程,每个线程分别打印ABC,并按照ABC的顺序执行十次

    题目可以使用多种不同的方式解决,下面我们分别使用 Condition 等待唤醒机制、Semaphore 信号量、CountDownLatch 闭锁、Thread.join() 方法四种方式实现题目要求。

    一、使用一个 ReentrantLock 和 三个 Condition 来实现:

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 题目要求:ABC三个线程顺序执行10次
     * 实现思路:使用一个ReentrantLock 和 三个 Condition 来实现
     */
    public class PrintABCUsingCondition
    {
        private static ReentrantLock lock = new ReentrantLock();
        private static Condition conditionA = lock.newCondition();
        private static Condition conditionB = lock.newCondition();
        private static Condition conditionC = lock.newCondition();
    
        public void execute(String flag)
        {
            lock.lock();
    
            for (int i = 1 ; i <= 10 ; i++){
                if ("A".equals(flag)) print(flag, conditionA, conditionB);
                if ("B".equals(flag)) print(flag, conditionB, conditionC);
                if ("C".equals(flag)) print(flag, conditionC, conditionA);
            }
    
            lock.unlock();
        }
    
        private void print(String name, Condition currentThread, Condition nextThread)
        {
            try{
                System.out.println(Thread.currentThread().getName()  + "-" + name);
                nextThread.signal();
                currentThread.await();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) throws InterruptedException
        {
            PrintABCUsingCondition myTask = new PrintABCUsingCondition();
    
            new Thread(() -> myTask.execute("A")).start();
            //必须确保线程A比另外两个线程先拿到ReentrantLock,所以让主线程sleep一段时间
            Thread.sleep(500);
            new Thread(() -> myTask.execute("B")).start();
            new Thread(() -> myTask.execute("C")).start();
        }
    }

    二、基于 Semaphore 信号量来实现:

    import java.util.concurrent.Semaphore;
    
    /**
     * 题目要求:ABC三个线程顺序执行10次
     * 实现思路:使用一个Semaphore信号量来实现
     */
    class PrintABCUsingSemaphore
    {
        private Semaphore semaphoreA = new Semaphore(1);
        private Semaphore semaphoreB = new Semaphore(0);
        private Semaphore semaphoreC = new Semaphore(0);
    
        private void printA(){
            print("A", semaphoreA, semaphoreB);
        }
    
        private void printB(){
            print("B", semaphoreB, semaphoreC);
        }
    
        private void printC(){
            print("C", semaphoreC, semaphoreA);
        }
    
        private void print(String name, Semaphore currentSemaphore, Semaphore nextSemaphore)
        {
            for (int i = 0; i < 10; i++){
                try {
                    currentSemaphore.acquire();
                    System.out.println(Thread.currentThread().getName() +" print "+ name);
                    nextSemaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args)
        {
            PrintABCUsingSemaphore printABC = new PrintABCUsingSemaphore();
            new Thread(() -> printABC.printA()).start();
            new Thread(() -> printABC.printB()).start();
            new Thread(() -> printABC.printC()).start();
        }
    }

    三、基于 CountDownLatch 闭锁来实现:

    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.*;
    
    /**
     *  题目要求:ABC三个线程顺序执行10次
     *  实现思路:使用 CountDownLatch 来实现:
     * (1)定义dependLatch(所依赖的latch名)、selfLatch(自己的latch名)
     * (2)首先调用所依赖的latch的await()方法,如果所依赖的latch的count为0,则重置所依赖的latch并打印需要输出的,最后将自身的count减去
     * (3)sum为需要执行的次数
     */
    public class PrintABCUsingCountDownLatch implements Runnable {
    
        private static Map<String, CountDownLatch> countDownLatchMap = new HashMap<>();
    
        private String dependLatch;
        private String selfLatch;
    
        private PrintABCUsingCountDownLatch(String dependLatch, String selfLatch)
        {
            this.dependLatch = dependLatch;
            this.selfLatch = selfLatch;
        }
    
        @Override
        public void run()
        {
            for (int i = 0; i < 10; i++)
            {
                try {
                    countDownLatchMap.get(dependLatch).await();
                    countDownLatchMap.put(dependLatch, new CountDownLatch(1));
    
                    System.out.println(Thread.currentThread().getName() + ":" + selfLatch);
    
                    countDownLatchMap.get(selfLatch).countDown();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args)
        {
            String latchA = "A";
            String latchB = "B";
            String latchC = "C";
    
            countDownLatchMap.put(latchA, new CountDownLatch(1));
            countDownLatchMap.put(latchB, new CountDownLatch(1));
            countDownLatchMap.put(latchC, new CountDownLatch(1));
    
            //创建三个线程,但是此时由于三个CountDownLatch都不为0,所以三个线程都处于阻塞状态
            Thread threadA = new Thread(new PrintABCUsingCountDownLatch(latchC, latchA));
            Thread threadB = new Thread(new PrintABCUsingCountDownLatch(latchA, latchB));
            Thread threadC = new Thread(new PrintABCUsingCountDownLatch(latchB, latchC));
            threadA.start();
            threadB.start();
            threadC.start();
            //latchC 阻塞了 latchA;调用latchC的countDown()方法,先让latchC为0,使latchA先运行
            countDownLatchMap.get(latchC).countDown();
        }
    

    四、 使用 Thread.join() 方法来实现:

    /**
     * 题目要求:ABC三个线程顺序执行10次
     * 实现思路:使用 Thread.join() 方法来实现
     */
    public class PrintABCUsingJoin
    {
        public static void main(String[] args)
        {
            Thread t0 = new Thread(new Work((null)));
            Thread t1 = new Thread(new Work((t0)));
            Thread t2 = new Thread(new Work((t1)));
            t0.start();
            t1.start();
            t2.start();
        }
    }
    
    class Work implements Runnable
    {
        private Thread beforeThread;
        public Work(Thread beforeThread)
        {
            this.beforeThread = beforeThread;
        }
    
        @Override
        public void run()
        {
            //调用前面线程的join方法
            if(beforeThread != null)
            {
                try{
                    beforeThread.join();
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            System.out.println("当前线程:" + Thread.currentThread().getName());
        }
    }
    展开全文
  • 文章介绍4种方法,简单易懂,通过4个demo抛砖引玉。 目录 在子线程中通过join()方法指定顺序 在主线程中通过join()...通过join()方法使当前线程“阻塞”,等待指定线程执行完毕后继续执行。举例:在线程thread...
  • 如何让多线程按顺序执行

    千次阅读 2020-09-03 16:27:25
    比如在线程thread2中,加上一句thread1.join(),其意义在于,当前线程2运行到此行代码时会进入阻塞状态,直到线程thread1执行完毕后,线程thread2才会继续运行,这就保证线程thread1与线程thread2的运行顺序 ...
  • 让多线程按顺序执行的几种方法

    万次阅读 多人点赞 2019-09-05 14:23:58
    文章介绍4种方法,简单易懂,通过4个demo抛砖引玉。 目录 在子线程中通过join()方法指定顺序 在主线程中通过join()方法指定顺序 ...通过join()方法使当前线程“阻塞”,等待指定线程执行完毕后继续执行。举例:在...
  • 文章目录1、通过Thread的join方法2、FutureTask3、CountDownLatch(倒计数)4、wait、notify5、Condition(条件变量)6、CyclicBarrier(回环栅栏)5、线程池5.1、单线程化线程池5.2、多线程化线程池 1、通过Thread的...
  • 如何保证线程按顺序执行完成?

    千次阅读 2021-03-10 02:59:19
    我们知道线程执行时机是CPU时间片轮询策略决定的,那么有没有办法让线程按指定的顺序执行呢?下面就通过JAVA提供的两种API来实现。1.首先定义三个线程对象,用来模拟多线程执行顺序。staticThreadthread1=newThread...
  • 三个线程t1、t2、t3。确保三个线程,t1 执行完后 t2 执行,t2 执行完后 t3 执行。 一、使用 CountDownLatch 二、使用 join thread.join 把指定的线程... // T1、T2、T3三个线程顺序执行 public static void main(Stri
  • 14 如何多个线程按顺序执行

    千次阅读 2020-08-12 21:48:06
    如何控制多线程执行顺序? 方法一:使用join()方法让一个线程强制运行 调用一个线程的join()方法就可以让这个线程强制运行,并且它会阻塞主线程的运行。 原理:调用join方法,会调用join(0)方法,当参数为0时,会...
  • Java—如何保证线程按顺序执行

    千次阅读 2020-01-08 18:41:09
    当多个线程执行任务时,可以通过Thread.join()方法保证线程执行顺序,其内部是通过调用主线程的wait方法,使主线程等待;当子线程执行完成后,再唤醒主线程。 下面写一个简单的实例:创建ABCD四个线程,每个线程...
  • 在多线程中有多种方法让线程按特定顺序执行,可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会...
  • 使用单线程线程池来实现 另一种保证线程顺序执行的方法是使用一个单线程的线程池,这种线程池中只有一个线程,相应的,内部的线程会加入的顺序来执行。 import java.util.concurrent.ExecutorService; import ...
  • java多线程实现顺序执行

    千次阅读 2022-02-14 14:06:42
    1.使用线程的join方法 public static void main(String[] args) { final Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println("起床"); } }); final Thread t2
  • 就是让线程thread执行完成后,再执行后面的代码逻辑。 实现原理: join方法内部的实现是synchronized + object.wait()方法,比如在主线程main中执行 t.join(); 主线程main会持有调用join方法的线程t的锁,join方法...
  • 只要了解过多线程,我们就知道线程开始的顺序执行顺序是不一样的。如果只是创建三个线程然后执行,最后的执行顺序是不可预期的。这是因为在创建完线程之后,线程执行的开始时间取决于CPU何时分配时间片,线程...
  • 本文使用了8种方法实现在多线程中让线程按顺序运行的方法,涉及到多线程中许多常用的方法,不止为了知道如何让线程按顺序运行,更是让读者对多线程的使用有更深刻的了解。使用的方法如下: [1] 使用线程的join方法 ...
  • 如何保证多个线程按一定顺序执行

    千次阅读 2019-05-13 14:32:19
    假设现在有三个线程t1、t2和t3 让t2在t1完成后执行,t3在t2完成后执行 自定义Thread类 public class Thread extends java.lang.Thread { private String str ; private int time; public Thread(String str,int ...
  • 3种不同的队列类 q=Queue(maxsize):创建一个FIFO(first-in first-out,先进先出)队列。maxsize是队列中金额以放入的项的最大数量。 如果省略maxsize参数或将它置为0,队列大小将无穷大。 q=LifoQueue(maxsize):...
  • 线程按顺序执行7种方法

    千次阅读 2019-03-25 09:50:54
    前言本文使用了7中方法实现在多线程中让线程按顺序运行的方法,涉及到多线程中许多常用的方法,不止为了知道如何让线程按顺序运行,更是让读者对多线程的使用有更深刻的了解。 使用的方法如下: [1] 使用线程的join...
  • Thread类构造方法:1.Thread();2.Thread(String name);3.Thread(Runable r);4.Thread(Runable r, String name); thread类常用方法:start();//启动线程getId();...//判断线程是否活...
  • } 执行结果如下: 现在他就是顺序执行的了,主线程在执行到join时就需要等待当前线程的run 方法执行完后才能重新获得控制权,所以在现象上表现出来的就是顺序执行线程,而不是先start所有线程(先执行完主线程),...
  • 一、Thread的join方法 public static void ... System.out.println(“线程1执行”)); Thread t2 = new Thread(() -> { try { t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } System

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 364,433
精华内容 145,773
关键字:

如何保证线程按顺序执行