標籤:java 多線程 java
我們知道線程能通過繼承Thread和實現Runnable介面來實現,但是,他們都有一個弊端,就是run之後不能有返回值,當然我們可以通過向線程中傳入變數的方式解決,但是貌似又不總是那麼可靠,還好,java給了我們另外的介面Callable和Future.
我們先來看看他們的結構:
<span style="font-size:14px;">public interface Callable<V>{ V call() throws Exception; } public interface Future<V>{ V get() throws Exception; V get(long timeout, TimeUnit unit)throws Exception; void cancle(boolean mayInterrput); boolean isCancelled(); boolean isDone(); }</span>
在Callable中我們可以看到調用call的時候是可以返回V的,而Future是幹嘛的呢,他可以用來儲存非同步計算的結果。
第一個get和被阻塞直至計算完成並返回結果,第二個假如逾時,會拋出TImeoutException異常。
如果計算還在繼續,isDone()會返回false,假如已經完成,則返回true.
cancle可以取消計算,如果還沒開始則不會被運行,假如已經開始,且mayInterrupt為true,他會被中斷。
java中還存在FutureTask封裝器,可以將Callable轉化成Future和Runnable.例如:
<span style="font-size:14px;">public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<Integer> callable = new ...; FutureTask<Integer> task = new FutureTask<Integer>(callable); Thread thread = new Thread(task); thread.start(); Integer integer = task.get(); }</span> 好了,到了我感覺很牛逼的東西出場的時候了-----執行器
假如我們建立大量的線程,然後又終止他們系統是需要很大的花銷的。那麼我們可不可以複用他們呢,可以,調用線程池(thread pool)。
執行器(Executor)類有很多的Factory 方法來構建線程池。以下是線程池的匯總:
newCachedThreadPool必要時建立新線程,空閑線程會被保留60秒
newFixedThreadPool該線程池包含固定數量的線程,空閑線程會一直被保留
newSingleThreadExecutor只有一個線程的“池”,該線程按照順序執行每一個提交的任務
newScheduledThreadPool用於預定執行而構建的固定線程池,代替java.util.Timer
newSingleScheduledExecutor用於預定執行而建立的單線程“池”
接下來我們只說前三個。
他們都是實現了ExecutorService介面的ThreadPoolExecutor類,下面方法可以提交一個任務
<span style="font-size:14px;"> Future<?> submit(Runnable task); Future<T> submit(Runnable task, T result); Future<T> submit(Callable task);</span>
第一個,因為Runnable 自身不返回,而卻沒有足夠資訊制定返回的對象是什麼,所以我們可以看見返回的是Future<?>,其實當調用Future的get時,只是簡單的返回null而已,當然其他的方法依舊能用。
第二個,也是一個Runnable對象,但是用get時,會返回置頂的result對象。
第三個,傳入一個Callable對象,並返回指定值。
當然在使用完一個線程池後記得shutdown.
下面我們來看一個樣本:
<span style="font-size:14px;">class Counter implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName() + "counting"); int i; for (i = 0; i < 60; i++){ if (i % 10 == 0){ System.out.println(); } System.out.print(i + " "); } return i; }}public class ForCallable { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService pool = Executors.newCachedThreadPool(); Counter counter = new Counter(); Future<Integer> future = pool.submit(counter); System.out.println(Thread.currentThread().getName() + ": i am sleeping"); Thread.sleep(5000); System.out.println("get value:" + future.get()); pool.shutdown(); }}</span>
java 多線程再探