這一篇博文是【大數據技術●降龍十八掌】系列文章的其中一篇,點擊查看目錄:大數據技術●降龍十八掌
- 系列文章:
- 【十八掌●基本功篇】第一掌:Java之IO
【十八掌●基本功篇】第一掌:Java之多線程–1-一些概念
【十八掌●基本功篇】第一掌:Java之多線程–2-join、同步、死鎖、等待
【十八掌●基本功篇】第一掌:Java之多線程–3-線程池
線程池的基本思想是開闢一塊內存空間,裏面存放了很多的線程,池中的線程執行調度由池管理器來處理,當有線程任務時,從池中取一個線程,自行完成後線程對象歸池,這樣可以避免反覆創建線程對象所帶來的性能開銷,節省系統的資源。
線程池的好處一是通過重複利用已經存在的線程,降低了頻繁創建和銷燬線程所帶來的消耗,因爲不用等待創建線程,也提高了程序響應速度。二是線程池統一對線程進行分配和監控,提高了線程的可管理性,也控制了線程的總數,不會無限制地創建線程。
(1) 常見線程池
舉個例子:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by 鳴宇淳 on 2017/12/12.
*/
public class Demo1 {
public static void main(String[] args) {
//三種線程池
// 1.創建一個固定大小的線程池,
//ExecutorService pool= Executors.newFixedThreadPool(3);
// 2.創建一個單個worker線程的Executors,保證多個線程以指定的順序執行
//ExecutorService pool=Executors.newSingleThreadExecutor();
// 3.創建一個可根據需要創建新線程池。
ExecutorService pool=Executors.newCachedThreadPool();
//創建多個線程
Thread t1=new Thread(new MyThread("線程1"));
Thread t2=new Thread(new MyThread("線程2"));
Thread t3=new Thread(new MyThread("線程3"));
Thread t4=new Thread(new MyThread("線程4"));
Thread t5=new Thread(new MyThread("線程5"));
Thread t6=new Thread(new MyThread("線程6"));
//將線程放入池中執行,向線程池中投放任務
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
pool.execute(t6);
//關閉線程池
pool.shutdown();
}
}
/**
* Created by 鳴宇淳 on 2017/12/12.
*/
public class MyThread implements Runnable {
private String name = "";//線程的名字
public MyThread(String name) {
this.name = name;
}
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(500);
System.out.println(name + ":正在執行" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
這個例子中可以看到:
第一種:定義了一個3個大小的線程池,放入6個線程執行,是前三個先執行,有一個執行完畢後,再執行剩下的,最多有三個線程在執行。
第二種:線程是根據設置的順序,依次執行的,沒有併發的狀態。
第三種:會根據運行時的需要,按需創建新的線程。
(2) 延遲線程池
延遲線程池可以設置多長時間後執行某一個線程。
具體看以下實例:
import java.util.Date;
/**
* Created by 鳴宇淳 on 2017/12/13.
*/
public class ScheduledThreadDemo {
public static void main(String[] args) {
//創建一個延時線程池
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
Thread t1 = new Thread(new MyThread2("線程1"));
Thread t2 = new Thread(new MyThread2("線程2"));
Thread t3 = new Thread(new MyThread2("線程3"));
Thread t4 = new Thread(new MyThread2("線程4"));
System.out.println("開始運行時間:" + new Date() + "\n================");
pool.execute(t1);
pool.execute(t2);
//延時5秒後,執行線程t3
pool.schedule(t3, 5, TimeUnit.SECONDS);
//延時10秒後,執行線程t4
pool.schedule(t4, 10, TimeUnit.SECONDS);
pool.shutdown();
}
}
public class MyThread2 implements Runnable {
private String name = "";//線程的名字
public MyThread2(String name) {
this.name = name;
}
public void run() {
System.out.println(new Date() + "_" + name + ":正在執行");
}
}
輸出爲:
開始運行時間:Wed Dec 13 08:39:13 CST 2017
================
Wed Dec 13 08:39:13 CST 2017_線程1:正在執行
Wed Dec 13 08:39:13 CST 2017_線程2:正在執行
Wed Dec 13 08:39:18 CST 2017_線程3:正在執行
Wed Dec 13 08:39:23 CST 2017_線程4:正在執行
(3) 自定義線程池
舉個例子:
/**
* Created by 鳴宇淳 on 2017/12/13.
*/
public class CustomThreadPool {
public static void main(String[] args) {
//創建隊列
BlockingQueue<Runnable> bqueue=new ArrayBlockingQueue<Runnable>(20);
//創建一個自定義的線程池
// 1.第一個參數是池中保存的核心線程數
// 2.第二個參數是池中允許的最大線程數
// 3.第三個參數是:線程池維護線程所允許的空閒時間。
// 當線程池中的線程數量大於corePoolSize的時候,
// 如果這時沒有新的任務提交,核心線程外的線程不會立即銷燬,而是會等待,
// 直到等待的時間超過了keepAliveTime
// 4.第四個參數爲時間單位
// 5.第五個參數是用於保存線程任務的隊列。
ThreadPoolExecutor pool=new ThreadPoolExecutor(2,5,1000, TimeUnit.MILLISECONDS,bqueue);
Thread t1 = new Thread(new MyThread2("線程1"));
Thread t2 = new Thread(new MyThread2("線程2"));
Thread t3 = new Thread(new MyThread2("線程3"));
Thread t4 = new Thread(new MyThread2("線程4"));
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.shutdown();
}
}