线程顺序执行方式

前言

GitHub:https://github.com/yihonglei/thinking-in-concurrent

概述

T1、T2、T3如何保证线程顺序执行?

直接上Demo吧!

一 Join方法

Join方法是最常用的方式,底层通过wait即加了synchronized同步锁和notify通知逻辑实现。

Join实现原理:https://blog.csdn.net/u010983881/article/details/80257703

package com.jpeony.concurrent.threadorder;

/**
 * join控制线程顺序执行
 *
 * @author yihonglei
 */
public class ThreadJoinOrder {
    public static void main(String[] args) throws InterruptedException {
        // 创建线程
        Thread t1 = new Thread(new Work(), "Thread-1");
        Thread t2 = new Thread(new Work(), "Thread-2");
        Thread t3 = new Thread(new Work(), "Thread-3");

        // 调用join
        t1.join();
        t2.join();
        t3.join();

        // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }

    static class Work implements Runnable {
        @Override
        public void run() {
            System.out.println("thread start:" + Thread.currentThread().getName());
        }
    }
}

运行结果:

 线程顺序执行方式_第1张图片

二 FutureTask

通过FutureTask的get()方法阻塞特性,控制线程顺序。

package com.jpeony.concurrent.threadorder;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * FutureTask控制线程顺序,通过get方法阻塞获取上一个线程结果,只有当上一个线程执行完成并返回结果时,才继续执行下一个线程。
 *
 * @author yihonglei
 */
public class FutureTaskOrder {
    public static void main(String[] args) {
        // 创建FutureTask
        FutureTask task1 = new FutureTask<>(new Work(null));
        FutureTask task2 = new FutureTask<>(new Work(task1));
        FutureTask task3 = new FutureTask<>(new Work(task2));

        // 创建线程
        Thread t1 = new Thread(task1, "Thread-1");
        Thread t2 = new Thread(task2, "Thread-2");
        Thread t3 = new Thread(task3, "Thread-3");

        // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }

    static class Work implements Callable {
        private FutureTask beforeTask;

        Work(FutureTask beforeTask) {
            this.beforeTask = beforeTask;
        }

        @Override
        public String call() throws Exception {
            if (beforeTask != null) {
                // 阻塞等待,上一个线程执行完,才能继续执行
                beforeTask.get();
                System.out.println("thread start:" + Thread.currentThread().getName());
            } else {
                System.out.println("thread start:" + Thread.currentThread().getName());
            }
            return "Result " + Thread.currentThread().getName();
        }
    }
}

运行结果:

线程顺序执行方式_第2张图片

三 NewSingleThreadExecutor

Executors.newSingleThreadExecutor():线程池只有一个工作线程,工作线程从BlockingQueue阻塞有序队列取任务执行,

从而保证线程的顺序性执行。

线程池实现原理:https://blog.csdn.net/yhl_jxy/article/details/86677049

package com.jpeony.concurrent.threadorder;

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

/**
 * Executors.newSingleThreadExecutor():线程池只有一个工作线程,工作线程从BlockingQueue阻塞有序队列取任务执行,
 * 从而保证线程的顺序性执行。
 *
 * @author yihonglei
 */
public class NewSingleThreadExecutorOrder {
    public static void main(String[] args) {
        // 单个线程池,保证线程依次执行顺序
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        // 创建线程
        Thread t1 = new Thread(new Work("one"));
        Thread t2 = new Thread(new Work("two"));
        Thread t3 = new Thread(new Work("three"));

        // 提交线程池
        executorService.submit(t1);
        executorService.submit(t2);
        executorService.submit(t3);

        // 关闭线程池
        executorService.shutdown();
    }

    static class Work implements Runnable {
        private String orderName;

        Work(String orderName) {
            this.orderName = orderName;
        }

        @Override
        public void run() {
            System.out.println("thread start:" + orderName);
        }
    }
}

运行结果:

线程顺序执行方式_第3张图片

四 CompletableFuture

CompletableFuture为Java8新特性。

CompletableFuture使用说明:https://juejin.im/post/5edf454c518825433a57c4c9

package com.jpeony.concurrent.threadorder;

import java.util.concurrent.CompletableFuture;

/**
 * CompletableFuture顺序执行任务
 *
 * @author yihonglei
 */
public class CompletableFutureOrder {
    public static void main(String[] args) {
        CompletableFuture cf = CompletableFuture.supplyAsync(() -> {
            System.out.println("Thread-1");
            return "one";
        });

        cf.thenRun(() -> {
            System.out.println("Thread-2");
        });

        cf.thenRun(() -> {
            System.out.println("Thread-3");
        });
    }
}

运行结果:

线程顺序执行方式_第4张图片

五 队列顺序性

通过阻塞队列+while循环控制线程的顺序性,或者通过ArrayList控制线程的顺序,

但是需要在每个线程执行完成时自己从队列移出元素。

package com.jpeony.concurrent.threadorder;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 通过阻塞队列+while循环控制线程的顺序性,或者通过ArrayList控制线程的顺序,但是需要在每个线程执行完成时自己从队列移出元素。
 *
 * @author yihonglei
 */
public class BlockingQueueOrder {
    public static void main(String[] args) throws InterruptedException {
        // 创建线程
        Thread t1 = new Thread(new Work(), "Thread-1");
        Thread t2 = new Thread(new Work(), "Thread-2");
        Thread t3 = new Thread(new Work(), "Thread-3");
        // 队列保证顺序性
        BlockingQueue blockingQueue = new LinkedBlockingQueue<>();
        blockingQueue.add(t1);
        blockingQueue.add(t2);
        blockingQueue.add(t3);

        for (int i = 0; i < 3; i++) {
            Thread take = blockingQueue.take();
            take.start();
            while (take.isAlive()) ;
        }

        // 主线程保持存活
        Thread.sleep(3000);
    }

    static class Work implements Runnable {
        @Override
        public void run() {
            System.out.println("thread start:" + Thread.currentThread().getName());
        }
    }
}

运行结果:

线程顺序执行方式_第5张图片

六 CountDownLatch

CountDownLatch控制线程执行顺序,通过await方法为0时,线程才会执行特性,阻塞线程执行,通过上一个线程执行完成,

减掉下一个线程的计数器,使下一个线程计数器为0,线程变为可执行,来控制线程执行顺序。

CountDownLatch实现原理:https://blog.csdn.net/yhl_jxy/article/details/87181895

package com.jpeony.concurrent.threadorder;

import java.util.concurrent.CountDownLatch;

/**
 * CountDownLatch控制线程执行顺序,通过await方法为0时,线程才会执行特性,阻塞线程执行,通过上一个线程执行完成,
 * 减掉下一个线程的计数器,使下一个线程计数器为0,线程变为可执行,来控制线程执行顺序。
 *
 * @author yihonglei
 */
public class CountDownLatchOrder {
    public static void main(String[] args) {
        // 计数器为0
        CountDownLatch threadC1 = new CountDownLatch(0);
        // 计数器为1
        CountDownLatch threadC2 = new CountDownLatch(1);
        // 计算器为2
        CountDownLatch threadC3 = new CountDownLatch(1);

        // threadC1计数器为0,t1线程执行,然后threadC2计数器被减为0
        Thread t1 = new Thread(new Work(threadC1, threadC2), "Thread-1");
        // threadC2计数器为0,t2线程执行,然后threadC3计数器被减为0
        Thread t2 = new Thread(new Work(threadC2, threadC3), "Thread-2");
        // threadC3计数器为0,t3线程执行
        Thread t3 = new Thread(new Work(threadC3, threadC3), "Thread-3");
        
        // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }

    static class Work implements Runnable {
        // 当前要执行线程的计数器
        private CountDownLatch current;
        // 下一个要执行线程的计数器
        private CountDownLatch next;

        Work(CountDownLatch current, CountDownLatch next) {
            this.current = current;
            this.next = next;
        }

        @Override
        public void run() {
            try {
                // 计数器为0,则可执行,否则线程被阻塞
                current.await();
                System.out.println("thread start:" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                // 计数器减1,将计数器变为0,通知等待线程尝试获取锁执行
                next.countDown();
            }
        }
    }
}

运行结果:

线程顺序执行方式_第6张图片

你可能感兴趣的:(Thinking,In,Concurrent,#,---多线程/高并发,线程顺序执行,CountDownLatch,BlockingQueue,Future,Executor)