您好,登錄后才能下訂單哦!
線程池是一種多線程處理形式,處理過程中將任務(wù)添加到隊列,然后在創(chuàng)建線程后自動啟動這些任務(wù)。線程池線程都是后臺線程。每個線程都使用默認的堆棧大小,以默認的優(yōu)先級運行,并處于多線程單元中。如果某個線程在托管代碼中空閑(如正在等待某個事件),則線程池將插入另一個輔助線程來使所有處理器保持繁忙。如果所有線程池線程都始終保持繁忙,但隊列中包含掛起的工作,則線程池將在一段時間后創(chuàng)建另一個輔助線程但線程的數(shù)目永遠不會超過最大值。超過最大值的線程可以排隊,但他們要等到其他線程完成后才啟動。
首先,看一下這種線程池的創(chuàng)建方法:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
從構(gòu)造方法可以看出,它創(chuàng)建了一個單線程化的線程池,它只會用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照指定順序執(zhí)行。
那么,如何使用newSingleThreadExecutor呢?我們來舉個例子:
public class OneMoreStudy {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
try {
SimpleDateFormat sdf = new SimpleDateFormat(
"HH:mm:ss");
System.out.println("運行時間: " +
sdf.format(new Date()) + " " + index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
singleThreadExecutor.shutdown();
}
}
因為該線程池類似于單線程執(zhí)行,所以先執(zhí)行完前一個任務(wù)后,再順序執(zhí)行下一個任務(wù),
運行結(jié)果如下:
運行時間: 08:54:17 0
運行時間: 08:54:19 1
運行時間: 08:54:21 2
運行時間: 08:54:23 3
運行時間: 08:54:25 4
有的同學(xué)可能會質(zhì)疑:既然類似于單線程執(zhí)行,那么這種線程池還有存在的必要嗎?這里的單線程執(zhí)行指的是線程池內(nèi)部,從線程池外的角度看,主線程在提交任務(wù)到線程池時并沒有阻塞,仍然是異步的。
這個方法創(chuàng)建了一個固定大小的線程池,支持定時及周期性任務(wù)執(zhí)行。
首先看一下定時執(zhí)行的例子:
public class OneMoreStudy {
public static void main(String[] args) {
final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
System.out.println("提交時間: " + sdf.format(new Date()));
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println("運行時間: " + sdf.format(new Date()));
}
}, 3, TimeUnit.SECONDS);
scheduledThreadPool.shutdown();
}
}
使用該線程池的schedule方法,延遲3秒鐘后執(zhí)行任務(wù),運行結(jié)果如下:
提交時間: 09:11:39
運行時間: 09:11:42
再看一下周期執(zhí)行的例子:
public class OneMoreStudy {
public static void main(String[] args) {
final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
System.out.println("提交時間: " + sdf.format(new Date()));
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("運行時間: " + sdf.format(new Date()));
}
}, 1, 3, TimeUnit.SECONDS);
Thread.sleep(10000);
scheduledThreadPool.shutdown();
}
}
使用該線程池的scheduleAtFixedRate方法,延遲1秒鐘后每隔3秒執(zhí)行一次任務(wù),運行結(jié)果如下:
提交時間: 09:23:20
運行時間: 09:23:21
運行時間: 09:23:24
運行時間: 09:23:27
首先,看一下這種線程池的創(chuàng)建方法:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
從構(gòu)造方法可以看出,它創(chuàng)建了一個固定大小的線程池,每次提交一個任務(wù)就創(chuàng)建一個線程,直到線程達到線程池的最大值nThreads。線程池的大小一旦達到最大值后,再有新的任務(wù)提交時則放入***阻塞隊列中,等到有線程空閑時,再從隊列中取出任務(wù)繼續(xù)執(zhí)行。
那么,如何使用newFixedThreadPool呢?我們來舉個例子:
public class OneMoreStudy {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
SimpleDateFormat sdf = new SimpleDateFormat(
"HH:mm:ss");
System.out.println("運行時間: " +
sdf.format(new Date()) + " " + index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
fixedThreadPool.shutdown();
}
}
上面的例子中創(chuàng)建了一個固定大小為3的線程池,然后在線程池提交了5個任務(wù)。在提交第4個任務(wù)時,因為線程池的大小已經(jīng)達到了3并且前3個任務(wù)在運行中,所以第4個任務(wù)被放入了隊列,等待有空閑的線程時再被運行。運行結(jié)果如下(注意前3個任務(wù)和后2個任務(wù)的運行時間):
運行時間: 08:09:02 1
運行時間: 08:09:02 2
運行時間: 08:09:02 0
運行時間: 08:09:04 4
運行時間: 08:09:04 3
首先,看一下這種線程池的創(chuàng)建方法:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
從構(gòu)造方法可以看出,它創(chuàng)建了一個可緩存的線程池。當(dāng)有新的任務(wù)提交時,有空閑線程則直接處理任務(wù),沒有空閑線程則創(chuàng)建新的線程處理任務(wù),隊列中不儲存任務(wù)。線程池不對線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。如果線程空閑時間超過了60秒就會被回收。
那么,如何使用newCachedThreadPool呢?我們來舉個例子:
public class OneMoreStudy {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
final int index = i;
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
SimpleDateFormat sdf = new SimpleDateFormat(
"HH:mm:ss");
System.out.println("運行時間: " +
sdf.format(new Date()) + " " + index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
cachedThreadPool.shutdown();
}
}
因為這種線程有新的任務(wù)提交,就會創(chuàng)建新的線程(線程池中沒有空閑線程時),不需要等待,所以提交的5個任務(wù)的運行時間是一樣的,運行結(jié)果如下:
運行時間: 08:45:18 2
運行時間: 08:45:18 1
運行時間: 08:45:18 3
運行時間: 08:45:18 4
運行時間: 08:45:18 0
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。