標籤:java 多線程 線程池
Java實現多線程的3種方法:繼承Thread類、實現runnable介面、使用ExecutorService,Callable、Future實現有返回值的多線程。前2種線程的實現方式沒有返回值,第三種實現方式可以擷取線程執行的返回值。
一:繼承java.lang.Thread類
public class MyThread extends Thread {@Overridepublic void run() {System.out.println( "my thread begin." );try {// 休眠1000毫秒Thread.sleep( 1000 );} catch ( InterruptedException e ) {e.printStackTrace();}System.out.println( "my thread over." );}public static void main( String[] args ) {MyThread thread = new MyThread();thread.start();}}
二:實現java.lang.Runnable介面
public class MyThread implements Runnable {@Overridepublic void run() {System.out.println( "my thread begin." );try {// 休眠1000毫秒Thread.sleep( 1000 );// do something...} catch ( InterruptedException e ) {e.printStackTrace();}System.out.println( "my thread over." );}public static void main( String[] args ) {Thread thread = new Thread( new MyThread() );thread.start();}} 實現Runnable介面會比繼承Thread類更靈活一些,因為Java是單繼承,繼承了一個類就不能再繼承另外一個類,而介面可以實現多個。但是無論是繼承Thread類還是實現Runnable介面都不能擷取多線程的返回值,除非藉助額外的變數,在run方法中修改一個變數,在其他地方使用這個變數,這種實現方式比較"雞肋"。
三:實現java.util.concurrent.Callable介面
public class MyThread implements Callable<Object> {@Overridepublic Object call() throws Exception {System.out.println( "my thread begin." );try {// 休眠1000毫秒Thread.sleep( 1000 );} catch ( InterruptedException e ) {e.printStackTrace();}System.out.println( "my thread over." );return "ok";}public static void main( String[] args ) {// 建立一個線程池ExecutorService pool = Executors.newFixedThreadPool( 2 );Future<Object> f = pool.submit( new MyThread() );//關閉線程池pool.shutdown();try {System.out.println( f.get() );} catch ( InterruptedException e ) {e.printStackTrace();} catch ( ExecutionException e ) {e.printStackTrace();};}}
通過建立一個線程池提交一個Callable任務就可以通過Future類來擷取線程的返回值了,調用Future的get()方法的時候,如果任務沒有完成則阻塞直到任務完成。正如get()的注釋:Waits if necessary for the computation to complete, and then retrieves its result.
上面代碼中的ExecutorService介面繼承自Executor介面,Executor的實現基於生產者-消費者模式。提交任務的執行者是生產者(產生待完成的工作單元),執行任務的線程是消費者(消耗掉這些工作單元)。如果要實現一個生產者-消費者的設計,使用Executor通常是最簡單的方式。
Executors類提供了幾種建立線程池的方法,通過Exectors建立的線程池也實現了ExecutorService介面,方法如下:
1、固定大小的線程池:newFixedThreadPool(int nThreads)
建立固定大小的線程池。每次提交一個任務就建立一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執行異常而結束,那麼線程池會補充一個新線程。
2、單任務線程池:Executors.newSingleThreadExecutor()
創建一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當於單線程串列執行所有任務。如果這個唯一的線程因為異常結束,那麼會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的提交順序執行。
3、可變尺寸的線程池:Executors.newCachedThreadPool()
建立一個可快取的線程池。如果線程池的大小超過了處理任務所需要的線程,那麼就會回收部分空閑(60秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。此線程池不會對線程池大小做限制,線程池大小完全依賴於作業系統(或者說JVM)能夠建立的最大線程大小。
4、延遲線程池:Executors.newScheduledThreadPool(int corePoolSize)
建立一個大小無限的線程池。此線程池支援定時以及周期性執行任務的需求。
注意:shutdown()方法並不是終止線程的執行,而是禁止在這個Executor中添加新的任務。
java多線程、線程池的實現