java有四種線程池類型java
單線程線程池緩存
將線程提交到線程池中,提交的線程依次執行安全
Executors.newSingleThreadExecutor()
固定數目線程池多線程
提交到線程池的任務數大於線程池線程數量則等待函數
Executors.newFixedThreadPool(3)
無界可緩存線程池this
建立的線程數量無上限,第二個任務執行時若第一個任務已執行完則第二個任務執行時複用第一個任務執行時的線程。線程
Executors.newCachedThreadPool()
調度任務線程池code
ScheduledExecutorService service = Executors.newScheduledThreadPool(3); service.scheduleAtFixedRate(new MyThread1("線程"+i,i), 1, 1,TimeUnit.SECONDS); return service;
咱們用簡單的代碼來看下線程池運行的狀況對象
public class executorServiceTest { public static int number = 100; public static int i =1; public static ExecutorService getSingleThreadExecutor() { return Executors.newSingleThreadExecutor(); } public static ExecutorService getCachedThreadPool() { return Executors.newCachedThreadPool(); } public static ExecutorService getFixedThreadPool() { return Executors.newFixedThreadPool(3); }; public static ScheduledExecutorService getScheduledThreadPool() { ScheduledExecutorService service = Executors.newScheduledThreadPool(3); service.scheduleAtFixedRate(new MyThread1("線程"+i,i), 1, 1,TimeUnit.SECONDS); return service; }; public static void main(String[] args) { // 建立一個可重用固定線程數的線程池 ExecutorService pool = getSingleThreadExecutor(); // 建立實現了Runnable接口對象,Thread對象固然也實現了Runnable接口 Thread t1 = new MyThread1("線程1",1); t1.setName("線程1"); Thread t2 = new MyThread1("線程2",2); t2.setName("線程2"); Thread t3 = new MyThread1("線程3,",3); t3.setName("線程3"); Thread t4 = new MyThread1("線程4",4); t4.setName("線程4"); Thread t5 = new MyThread1("線程5",5); t5.setName("線程5"); // 將線程放入池中進行執行 execute沒返回值 submit有返回值 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); // 關閉線程池 pool.shutdown(); } } class MyThread1 extends Thread { public void run() { System.out.println(Thread.currentThread().getName() + "正在執行。。。"); executorServiceTest.number =executorServiceTest.number+ this.plusValue; executorServiceTest.i = executorServiceTest.i+1; System.out.println("加數:"+this.plusValue+",當前number的值:"+executorServiceTest.number); } private String name; private int plusValue; public MyThread1(String name,int plusValue) { super(); this.name = name; this.plusValue = plusValue; } }
上面代碼中的前四個靜態方法是獲取線程池實例接口
MyThread1是線程類 name plusValue 兩個屬性是爲了分析代碼構造的 經過構造函數給類的域賦值。
先看看單線程運行池的結果
pool-1-thread-1正在執行。。。 加數:1,當前number的值:101 pool-1-thread-1正在執行。。。 加數:2,當前number的值:103 pool-1-thread-1正在執行。。。 加數:3,當前number的值:106 pool-1-thread-1正在執行。。。 加數:4,當前number的值:110 pool-1-thread-1正在執行。。。 加數:5,當前number的值:115 能夠看到線程池裏只有一個線程 pool-1-thread-1 執行順序爲1 2 3 4 5 加數:1 表示 執行了提交的t1(參照構造函數)
改變提交順序
pool.execute(t1); pool.execute(t3); pool.execute(t2); pool.execute(t4); pool.execute(t5);
結果是這樣
pool-1-thread-1正在執行。。。 加數:1,當前number的值:101 pool-1-thread-1正在執行。。。 加數:3,當前number的值:104 pool-1-thread-1正在執行。。。 加數:2,當前number的值:106 pool-1-thread-1正在執行。。。 加數:4,當前number的值:110 pool-1-thread-1正在執行。。。 加數:5,當前number的值:115 只是執行的順序有改變 1 3 2 4 5
能夠單線程線程池是依次執行提交的任務 前一個任務沒完成後一個任務不會執行
可緩存線程池
若是線程池的大小超過了處理任務所須要的線程,線程60秒內未使用會被回收 ,若是新的任務被提交,線程池內有未使用的線程則線程會被複用。
提交線程
pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5);
第一次執行
pool-1-thread-1正在執行。。。 加數:1,當前number的值:101 pool-1-thread-3正在執行。。。 加數:3,當前number的值:104 pool-1-thread-5正在執行。。。 加數:5,當前number的值:109 pool-1-thread-2正在執行。。。 加數:2,當前number的值:111 pool-1-thread-4正在執行。。。 加數:4,當前number的值:115
第二次執行
pool-1-thread-3正在執行。。。 加數:3,當前number的值:103 pool-1-thread-1正在執行。。。 加數:1,當前number的值:104 pool-1-thread-5正在執行。。。 加數:5,當前number的值:109 pool-1-thread-2正在執行。。。 加數:2,當前number的值:111 pool-1-thread-4正在執行。。。 加數:4,當前number的值:115
兩次執行結果不一樣,再執行一次結果還有可能不一樣
從這個結果咱們看出線程池內有5個線程(咱們提交了5個任務),線程獲得CPU執行機會是隨機的。
咱們改變下線程池提交任務的代碼(模擬提交任務時線程池內有空閒線程,看是否會被複用)
pool.execute(t1); pool.execute(t2); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } pool.execute(t3); pool.execute(t4); pool.execute(t5);
這裏的Thread.sleep(1000)當前線程休眠1秒後在執行後面的提交t3,t4任務,這時執行t1,t2任務的線程 已經執行完但仍保流在線程池中
下面是運行結果
pool-1-thread-1正在執行。。。 加數:1,當前number的值:101 pool-1-thread-2正在執行。。。 加數:2,當前number的值:103 pool-1-thread-3正在執行。。。 加數:5,當前number的值:108 pool-1-thread-2正在執行。。。 加數:3,當前number的值:111 pool-1-thread-1正在執行。。。 加數:4,當前number的值:115
能夠看到線程pool-1-thread-1 pool-1-thread-2被複用了
固定數目線程池 運行結果
固定線程池是新來一個任務就會在線程池中建立一個線程,直到達到線程池的數量,線程池的大小一旦達到最大值就會保持不變
好比咱們建立一個數目爲3的固定線程池,提交兩個任務那麼線程池裏只會有兩個線程
提交的任務超過線程池線程數則等待線程池裏的任務執行完
定時任務線程池
同時建立多個定時任務線程池能夠用來模擬多線程安全
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); service.scheduleAtFixedRate(new MyThread1("線程"+i,i), 1, 1,TimeUnit.SECONDS);
這裏建立的定時任務每1秒執行一次,線程池裏只有一個線程。
ScheduledExecutorService service = Executors.newScheduledThreadPool(3); service.scheduleAtFixedRate(new MyThread1("線程"+i,i), 1, 1,TimeUnit.SECONDS);
這樣線程池裏就有3個線程,把3設爲1就跟上面的是同樣的效果了