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

有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();
    }


}

你可能感兴趣的:(如何让三个线程按顺序执行?)