線程執(zhí)行順序
我們先來看一個簡單的例子,我們顯示地創(chuàng)建三個線程t1、t2执虹、t3,按照聲明的順序聪姿,依次分別調(diào)用線程的start方法,線程的執(zhí)行順序是怎樣的乙嘀?程序執(zhí)行的結(jié)果會如何末购?:
public class ThreadOrderDemo {
// 顯示地創(chuàng)建三個線程,觀察執(zhí)行順序
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();
}
}
猜測程序執(zhí)行結(jié)果:
1.按照代碼順序執(zhí)行虎谢,依次為t1盟榴、t2、t3:
This is thread1
This is thread2
This is thread3
2.按照CPU調(diào)度規(guī)則婴噩,順序隨機:
This is thread1
This is thread3
This is thread2
我們經(jīng)過編輯器執(zhí)行擎场,會發(fā)現(xiàn)結(jié)果是2,按照CPU調(diào)度几莽,執(zhí)行順序隨機迅办。
那我們?nèi)绾巫尵€程有序執(zhí)行呢?以下有兩種方式章蚣。
方式一:使用join讓主線程等待
public static void main(String[] args) throws Exception {
// 方式一:使用join讓主線程等待
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
}
上述改寫主線程main方法站欺,使用Thread類提供的join方法,可以達到讓線程有序執(zhí)行的效果纤垂。
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方法峭沦,實質(zhì)上是通過調(diào)用Object的wait方法贾虽,讓主線程等待子線程執(zhí)行,子線程執(zhí)行完之后熙侍,主線程再執(zhí)行榄鉴。
方式二:使用線程池隊列
public class ThreadOrderDemo {
// 顯示地創(chuàng)建三個線程履磨,觀察執(zhí)行順序
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建立線程池隊列蛉抓,以保持線程有序執(zhí)行。
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);
}
序號 | 參數(shù)名 | 類型 | 含義 |
---|---|---|---|
1 | corePoolSize | int | 核心線程池大小 |
2 | maximumPoolSize | int | 最大線程池大小 |
3 | keepAliveTime | long | 線程最大空閑時間 |
4 | unit | TimeUnit | 時間單位 |
5 | workQueue | BlockingQueue<Runnable> | 線程等待隊列 |
6 | threadFactory | ThreadFactory | 線程創(chuàng)建工廠 |
7 | handler | RejectedExecutionHandler | 拒絕策略 |
上述Executors.newSingleThreadExecutor()實質(zhì)是LinkedBlockingQueue剃诅,創(chuàng)建了一個阻塞的安全線程隊列巷送,F(xiàn)IFO先進先出,所以可以達到線程有序執(zhí)行的目的矛辕。
推薦閱讀
談?wù)凧ava中hashCode和equals方法
談?wù)凧ava中==和equals到底有啥區(qū)別
從月薪5千到月薪3萬笑跛,優(yōu)秀的程序員