我們在之前的線程學習中,都是之間創建新的線程,顯性線程,用的時候開啓,用完銷燬,效率低且不安全
而且我們看到在阿里巴巴代碼規範規約中也是不建議顯式創建線程,建議使用線程池。
不管是繼承Thread還是遵從Runnable接口,都需要重寫Run方法,而且每一個線程對象有且只能執行一次,之後就會被銷燬。
利用Runnable接口來提供執行目標,而且藉助於Thread執行線程。
用生活中的例子來理解:
一個餐廳
服務人員
餐廳會按照餐桌比例安排服務員人數。
每一個服務員我們都可以看做是一個線程對象
需要告知服務器做什麼事情就可以了,相對於告知線程對象執行目標是什麼
當你來餐廳之前,服務員在這裏,你走之後,服務員依然在這類。
線程池 ==> 可以容納多個線程的容器
程序可以從線程池獲取線程來完成目標代碼
同時也可以將線程歸還給線程池。
省去了創建線程和銷燬線程這樣非常繁瑣的操作。節省時間。
線程池使用
public static ExecutorService newFixedThreadPool(int nThreads);
得到一個線程池對象,初始化參數是要求的當前線程池中的線程數
在這行代碼中, newFixedThreadPool是ExecutorService類中的方法
返回值是ExecutorService,參數是int類型的線程數量。
創建代碼示例爲:
ExecutorService service = Executors.newFixedThreadPool(5);
public Future submit(Runnable target);
從線程池中獲取一個線程對象,並且執行給定的Runnable接口實現類對象作爲執行目標
代碼如下:
package executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Thread1 implements Runnable{
@Override
public void run() {
System.out.println("啓動成功");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("執行代碼成功");
}
}
public class Demo1 {
public static void main(String[] args) {
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
Thread1 thread1 = new Thread1();
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(thread1);
// 因爲原本的5個線程都在被使用中,這裏需要等待5個線程執行完畢,出現空閒線程
// 來執行對應的目標代碼
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(new Thread1());
newFixedThreadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("匿名內部類");
}
});
// 4. 關閉線程池
// 一般不用關閉線程池,會隨着程序的退出而關閉
newFixedThreadPool.shutdown();
}
}
ps:匿名內部類的使用雖說很香,但是還不夠香,下邊我們就要從匿名內部類引出Lambda表達式。