美文网首页java文章阅读js css html
如何让三个线程按顺序执行?

如何让三个线程按顺序执行?

作者: 糯米团子123 | 来源:发表于2022-11-15 16:55 被阅读0次

    有T1、T2、T3三个线程,怎么让三个线程顺序执行?T1执行结束T2执行,T2执行结束T3执行。

    1. join()方法
     public static void main(String[] args) throws InterruptedException {
           Thread t1 = new Thread(()->{
               try {
                   Thread.sleep(2000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println("T1 执行完成...");
           });
           Thread t2 = new Thread(()->{
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println("T2 执行完成...");
           });
           Thread t3 = new Thread(()->{
               System.out.println("T3 执行完成...");
           });
    //使用 Thread.join() 等待线程执行完毕, 这种方式不优雅
           t1.start();
           t1.join();
           t2.start();
           t2.join();
           t3.start();
           t3.join();
        }
    
    1. wait()方法
      不推荐,不灵活
      wait()的线程必须要先执行,否则其他线程notify()是无法唤醒的。Object.wait()/notify()的这种方式,锁的使用方式一定是先wait()再notify()的。
    public static void main(String[] args) throws Exception{
            Thread2 t2 = new Thread2();
            Thread1 t1 = new Thread1(t2);
    
    //        Thread t3 = new Thread(t2);
    
            // 期望顺序 t1->t2->t3
            ExecutorService executorService = Executors.newFixedThreadPool(10);
            // 这里必须要让t2先执行才能正常执行,否则会一直处于wait()
    
            // 如果t1先拿到对象锁执行notify()无法唤醒t2,因为t2还没有拿到对象锁,未执行wait()
            // 因此同一个锁的执行顺序:wait()->notify()
            executorService.execute(t2);
            Thread.sleep(100);
            executorService.execute(t1);
    
            executorService.shutdown();
            while (!executorService.isTerminated()){
                // 等待所有线程执行结束
            }
            System.exit(0);
        }
    class Thread2 implements Runnable{
    
        @SneakyThrows
        @Override
        public void run() {
            synchronized (this){
                System.out.println("t2线程等待t1线程执行。。。");
                this.wait();
                System.out.println("t2线程等待t1线程执行。。。执行结束");
                System.out.println("t2线程执行");
            }
        }
    }
    
    class Thread1 implements Runnable{
        private final Object obj;
    
        public Thread1(Object obj) {
            this.obj = obj;
        }
    
        @Override
        public void run() {
            synchronized (obj){
                // notify()不会立马释放对象锁,释放情景: 1.synchronized代码块执行完成; 2.主动释放 wait();
                obj.notify();
                System.out.println("t1线程开始执行");
                System.out.println("t1线程执行结束");
            }
        }
    }
    
    1. 使用重入锁Condition.await()方法
    public class MyThread {
        static ExecutorService executorService = Executors.newFixedThreadPool(3);
    
        public static void main(String[] args) throws InterruptedException {
            MyLock myLock = new MyLock();
            Runnable t1 = myLock::thread1;
            Runnable t2 = myLock::thread2;
            Runnable t3 = myLock::thread3;
    
            executorService.submit(t1);
            executorService.submit(t2);
            executorService.submit(t3);
    
            Thread.sleep(1000);
            myLock.getLock().lock();
    
            // 唤醒线程t1
            myLock.getCondition1().signal();
    
            myLock.getLock().unlock();
    
            executorService.shutdown();
        }
    
        @Data
        static class MyLock{
            private ReentrantLock lock = new ReentrantLock();
            private Condition condition1 = lock.newCondition();
            private Condition condition2 = lock.newCondition();
            private Condition condition3 = lock.newCondition();
            public void thread1(){
                lock.lock();
                try {
                    System.out.println("线程t1等待执行。。。。");
                    condition1.await();// await()执行的前提是线程获取了对象的控制权,否则会报错:java.lang.IllegalMonitorStateException
                    System.out.println("线程t1执行。。。。");
                    condition2.signal(); // 唤醒线程
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
    
            public void thread2(){
                lock.lock();
                try {
                    System.out.println("线程t2等待执行。。。。");
                    condition2.await();// await()执行的前提是线程获取了对象的控制权,否则会报错:java.lang.IllegalMonitorStateException
                    System.out.println("线程t2执行。。。。");
                    condition3.signal();// 唤醒线程
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
    
            public void thread3(){
                lock.lock();
                try {
                    System.out.println("线程t3等待执行。。。。");
                    condition3.await();// await()执行的前提是线程获取了对象的控制权,否则会报错:java.lang.IllegalMonitorStateException
                    System.out.println("线程t3执行。。。。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        }
    }
    
    
    1. 建立单线程池:Executors.newSingleThreadExector()
      串行执行任务
    public class MyThread {
        static ExecutorService executorService = Executors.newSingleThreadExecutor();
    
        public static void main(String[] args) {
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("t1线程执行.....");
                }
            });
    
            Thread thread2 = new Thread(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    System.out.println("t2线程执行.....");
                }
            });
    
            Thread thread3 = new Thread(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    System.out.println("t3线程执行.....");
                }
            });
            executorService.submit(thread1);
            executorService.submit(thread2);
            executorService.submit(thread3);
            executorService.shutdown();//关闭线程池
        }
    }
    
    
    1. 计数器CountDownLatch
      检测到CountDownLatch计数器为0时就可以继续向下执行 不用管thread是否执行完毕。
      countDown()每调用一次 计数器减一
      await()计数器减到0时候唤醒当前线程继续执行
    package com.xuelangyun.web.controller;
    
    import lombok.SneakyThrows;
    
    import java.util.concurrent.CountDownLatch;
    
    /**
     * @author muxi.fs
     * @date 2022/11/16 16:08
     */
    public class MyThread {
        private static CountDownLatch countDownLatch1 = new CountDownLatch(1);
        private static CountDownLatch countDownLatch2 = new CountDownLatch(1);
    
        public static void main(String[] args) {
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("t1线程执行.....");
                    countDownLatch1.countDown();
                }
            });
    
            Thread thread2 = new Thread(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    countDownLatch1.await();
                    System.out.println("t2线程执行.....");
                    countDownLatch2.countDown();
                }
            });
    
            Thread thread3 = new Thread(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    countDownLatch2.await();
                    System.out.println("t3线程执行.....");
                    countDownLatch1.countDown();
                }
            });
    
            thread3.start();
            thread2.start();
            thread1.start();
        }
    }
    
    
    1. Senaphore信号量
      和CountDownLatch一样,作为信号来传递
    public class MyThread {
        static ExecutorService executorService = Executors.newFixedThreadPool(10);
        static Semaphore semaphore1 = new Semaphore(0);
        static Semaphore semaphore2 = new Semaphore(0);
    
        public static void main(String[] args) throws InterruptedException {
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程t1执行.....");
                    semaphore1.release(); // 信号量1  +1
                }
            });
            Thread thread2 = new Thread(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    semaphore1.acquire(); // 信号量-1  总数为0时候会等待
                    System.out.println("线程t2执行.....");
                    semaphore2.release();
                }
            });
            Thread thread3 = new Thread(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    semaphore2.acquire(); // 信号量-1  总数为0时候会等待
                    System.out.println("线程t3执行.....");
                }
            });
    
            executorService.submit(thread1);  // 信号量1先-1
            executorService.submit(thread2);
            executorService.submit(thread3);
    
            executorService.shutdown();
        }
    }
    
    1. FutureTask
      通过FutureTask阻塞的特性顺序执行,类似于单线程池执行
    public class MyThread {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            ExecutorService executorService = Executors.newFixedThreadPool(3);
            //Future<?> submit(Runnable task);
            Object t1 = executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程t1执行。。。。");
                }
            }).get();
            Object t2 = executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程t2执行。。。。");
                }
            }).get();
            Object t3 = executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程t3执行。。。。");
                }
            }).get();
            executorService.shutdown();
        }
    }
    

    executorService.submit()底层使用FutureTask实现

    1. CompletableFuture(推荐)
    public class MyThread {
        /**
         * CompletableFuture
         * 提供函数式编程的能力,可帮助我们完成复杂的线程的阶段行编程(CompletionStage)
         * @param args
         */
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newFixedThreadPool(3);
            Runnable t1 = () -> System.out.println("线程t1执行...");
            Runnable t2 = () -> System.out.println("线程t2执行...");
            Runnable t3 = () -> System.out.println("线程t3执行...");
    
            // 异步执行
            CompletableFuture.runAsync(t1,executorService).thenRun(t2).thenRun(t3);
            // 停止接受新任务,当已有任务将执行完,关闭线程池
            executorService.shutdown();
        }
    
    
    }
    
    

    相关文章

      网友评论

        本文标题:如何让三个线程按顺序执行?

        本文链接:https://www.haomeiwen.com/subject/rkolxdtx.html