谈谈Java中线程的执行顺序

2019-08-01  本文已影响0人  雨果是程序员

线程执行顺序

我们先来看一个简单的例子,我们显示地创建三个线程t1、t2、t3,按照声明的顺序,依次分别调用线程的start方法,线程的执行顺序是怎样的?程序执行的结果会如何?:

public class ThreadOrderDemo {
    // 显示地创建三个线程,观察执行顺序
    static Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("This is thread1");
        }
    });
    static Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("This is thread2");
        }
    });
    static Thread t3 = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("This is thread3");
        }
    });
    public static void main(String[] args) throws Exception {
        t1.start();
        t2.start();
        t3.start();
    }
}

猜测程序执行结果:
1.按照代码顺序执行,依次为t1、t2、t3:

This is thread1
This is thread2
This is thread3

2.按照CPU调度规则,顺序随机:

This is thread1
This is thread3
This is thread2

我们经过编辑器执行,会发现结果是2,按照CPU调度,执行顺序随机。
那我们如何让线程有序执行呢?以下有两种方式。

方式一:使用join让主线程等待

public static void main(String[] args) throws Exception {
        // 方式一:使用join让主线程等待
        t1.start();
        t1.join();

        t2.start();
        t2.join();
        
        t3.start();
    }

上述改写主线程main方法,使用Thread类提供的join方法,可以达到让线程有序执行的效果。

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

查看Thread类源码,可知,此处join方法,实质上是通过调用Object的wait方法,让主线程等待子线程执行,子线程执行完之后,主线程再执行。

方式二:使用线程池队列

public class ThreadOrderDemo {
    // 显示地创建三个线程,观察执行顺序
    static Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("This is thread1");
        }
    });
    static Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("This is thread2");
        }
    });
    static Thread t3 = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("This is thread3");
        }
    });
    static ExecutorService executor = Executors.newSingleThreadExecutor();
  
    public static void main(String[] args) throws Exception {
        // 方式二:使用线程池队列
       executor.submit(t1);
       executor.submit(t2);
       executor.submit(t3);
    }
}

上述使用J.U.C(java.util.concurrent)包中的ExecutorService建立线程池队列,以保持线程有序执行。

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

序号 参数名 类型 含义
1 corePoolSize int 核心线程池大小
2 maximumPoolSize int 最大线程池大小
3 keepAliveTime long 线程最大空闲时间
4 unit TimeUnit 时间单位
5 workQueue BlockingQueue<Runnable> 线程等待队列
6 threadFactory ThreadFactory 线程创建工厂
7 handler RejectedExecutionHandler 拒绝策略

上述Executors.newSingleThreadExecutor()实质是LinkedBlockingQueue,创建了一个阻塞的安全线程队列,FIFO先进先出,所以可以达到线程有序执行的目的。

推荐阅读

谈谈Java中hashCode和equals方法
谈谈Java中==和equals到底有啥区别
从月薪5千到月薪3万,优秀的程序员

上一篇下一篇

猜你喜欢

热点阅读