线程执行顺序
我们先来看一个简单的例子,我们显示地创建三个线程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()));
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue 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 |
线程等待队列 |
6 | threadFactory | ThreadFactory | 线程创建工厂 |
7 | handler | RejectedExecutionHandler | 拒绝策略 |
上述Executors.newSingleThreadExecutor()实质是LinkedBlockingQueue,创建了一个阻塞的安全线程队列,FIFO先进先出,所以可以达到线程有序执行的目的。
推荐阅读
谈谈Java中hashCode和equals方法
谈谈Java中==和equals到底有啥区别
从月薪5千到月薪3万,优秀的程序员