new Thread() {
@Override
public void run() {
// 業務邏輯
}
}.start();
複製代碼
一、newCachedThreadPool數據庫
public static void method() throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
final int index = i;
Thread.sleep(1000);
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " " + index);
}
});
}
}
複製代碼
執行結果bash
經過分析我看能夠看到,至始至終都由一個線程執行,實現了線程的複用,並無建立多餘的線程。服務器
若是當咱們的業務須要必定的時間進行處理,那麼將會出現什麼結果。咱們來模擬一下。ide
能夠明顯的看出,如今就須要幾條線程來交替執行。性能
二、newFixedThreadPool測試
這種方式能夠指定線程池中的線程數。舉個栗子,若是一間澡堂子最大隻能容納20我的同時洗澡,那麼後面來的人只能在外面排隊等待。若是硬往裏衝,那麼只會出現一種情景,摩擦摩擦...spa
首先測試一下最大容量爲一個線程,那麼會不會是咱們預測的結果。線程
public static void method_01() throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(1);
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
final int index = i;
executor.execute(() -> {
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + index);
});
}
executor.shutdown();
}
複製代碼
執行結果設計
咱們改成3條線程再來看下結果3d
優勢:兩個結果綜合說明,newFixedThreadPool的線程數是能夠進行控制的,所以咱們能夠經過控制最大線程來使咱們的服務器打到最大的使用率,同事又能夠保證及時流量忽然增大也不會佔用服務器過多的資源。
三、newScheduledThreadPool
該線程池支持定時,以及週期性的任務執行,咱們能夠延遲任務的執行時間,也能夠設置一個週期性的時間讓任務重複執行。 該線程池中有如下兩種延遲的方法。
測試一
public static void method_02() {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
long start = new Date().getTime();
System.out.println("scheduleAtFixedRate 開始執行時間:" +
DateFormat.getTimeInstance().format(new Date()));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = new Date().getTime();
System.out.println("scheduleAtFixedRate 執行花費時間=" + (end - start) / 1000 + "m");
System.out.println("scheduleAtFixedRate 執行完成時間:" + DateFormat.getTimeInstance().format(new Date()));
System.out.println("======================================");
}
}, 1, 5, TimeUnit.SECONDS);
}
複製代碼
執行結果
測試二
總結:以上兩種方式不一樣的地方是任務的執行時間,若是間隔時間大於任務的執行時間,任務不受執行時間的影響。若是間隔時間小於任務的執行時間,那麼任務執行結束以後,會立馬執行,至此間隔時間就會被打亂。
測試一
public static void method_03() {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
long start = new Date().getTime();
System.out.println("scheduleWithFixedDelay 開始執行時間:" +
DateFormat.getTimeInstance().format(new Date()));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = new Date().getTime();
System.out.println("scheduleWithFixedDelay執行花費時間=" + (end - start) / 1000 + "m");
System.out.println("scheduleWithFixedDelay執行完成時間:"
+ DateFormat.getTimeInstance().format(new Date()));
System.out.println("======================================");
}
}, 1, 2, TimeUnit.SECONDS);
}
複製代碼
執行結果
測試二
public static void method_03() {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
long start = new Date().getTime();
System.out.println("scheduleWithFixedDelay 開始執行時間:" +
DateFormat.getTimeInstance().format(new Date()));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = new Date().getTime();
System.out.println("scheduleWithFixedDelay執行花費時間=" + (end - start) / 1000 + "m");
System.out.println("scheduleWithFixedDelay執行完成時間:"
+ DateFormat.getTimeInstance().format(new Date()));
System.out.println("======================================");
}
}, 1, 2, TimeUnit.SECONDS);
}
複製代碼
執行結果
總結:一樣的,跟scheduleWithFixedDelay測試方法同樣,能夠測出scheduleWithFixedDelay的間隔時間不會受任務執行時間長短的影響。
四、newSingleThreadExecutor
這是一個單線程池,至始至終都由一個線程來執行。
public static void method_04() {
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
final int index = i;
executor.execute(() -> {
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + index);
});
}
executor.shutdown();
}
複製代碼
執行結果
線程池的做用主要是爲了提高系統的性能以及使用率。文章剛開始就提到,若是咱們使用最簡單的方式建立線程,若是用戶量比較大,那麼就會產生不少建立和銷燬線程的動做,這會致使服務器在建立和銷燬線程上消耗的性能可能要比處理實際業務花費的時間和性能更多。線程池就是爲了解決這種這種問題而出現的。
一樣思想的設計還有不少,好比數據庫鏈接池,因爲頻繁的鏈接數據庫,然而建立鏈接是一個很消耗性能的事情,全部數據庫鏈接池就出現了。