Java多線程

1.Runnable接口與Callable接口的區別

    Runnable接口中的方法簽名爲:public void run();該方法不能聲明拋出受檢查的異常,但在方法體內可以捕獲並處理異常;

    Callable<V>接口中的方法簽名:public V call() throws Exception;該方法能夠拋出受檢查的異常,能夠返回一個V類型的值;

    實現這兩個接口的對象都可以用來構造線程對象。

2.Future<V>接口

    該接口能夠封裝Callable接口的返回值,並提供了一系列的方法來獲取call方法的計算結果。

  • boolean cancel(boolean mayInterruptIfRunning):該方法試圖取消對任務的執行;
  • boolean isCancelled():如果在任務正常完成前將其取消,則返回 true;
  • boolean isDone():如果任務已完成,則返回 true。 可能由於正常終止、異常或取消而完成,在所有這些情況中,此方法都將返回 true;
  • V get():如有必要,則阻塞等待計算完成,然後獲取其結果;
  • V get(long timeout, TimeUnit unit):如有必要,最多等待爲使計算完成所給定的時間之後,獲取其結果,否則拋出異常
    FutureTask 類是 Future 的一個實現,並實現了Runnable接口,所以可通過 Executor 來執行。下面分別演示Future接口和FutureTask類的使用,單獨使用Future接口需要通過Executor.submit方法返回future對象,否則使用FutureTask類則可以使用excute來提交執行。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

class RetString implements Callable<String>{
	private String retString;
	public RetString(String s) {
		this.retString = s;
	}
	public String call() throws Exception{
		return retString;
	}
}
public class CallableThreadTest {

	public static void main(String[] args) throws 
	    InterruptedException, ExecutionException {
		/**
		 * 使用Future接口,需要使用submit方法提交任務,該方法返回一個future對象
		 */
		ExecutorService exec = Executors.newFixedThreadPool(2);
		Future<String>  future = exec.submit(new RetString("Hello World"));
		
		/**
		 * 使用FutureTask類,直接使用execute方法
		 */
		FutureTask<String> fTask = new FutureTask<String>(new RetString("Good Night"));
		exec.execute(fTask);
		
		if(future.isDone()) 
			System.out.println(future.get());
		if(fTask.isDone()) 
			System.out.println(fTask.get());
		
		exec.shutdown();
	}
}
3.使用Executor
    該接口提供一種將任務提交與每個任務將如何運行的機制(包括線程使用的細節、調度等)分離開來的方法;ExecutorService是該接口的一個子接口。通過Executors工廠類的靜態方法來創建ExecutorService接口對象。
  • static ExecutorService newCachedThreadPool():創建一個可根據需要創建新線程的線程池;
  • static ExecutorService newCachedThreadPool(ThreadFactory threadFactory):創建一個可根據需要創建新線程的線程池,在需要時使用提供的 ThreadFactory 創建新線程;
  • static ExecutorService newFixedThreadPool(int nThreads):創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程;
  • static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory);
  • static ExecutorService newSingleThreadExecutor():創建一個使用單個worker線程的Executor,以無界隊列方式來運行該線程。如果提交多個任務,這些任務將排隊,每個任務在下個任務開始i之前運行結束
  • static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) :創建一個線程池,它可安排在給定延遲後運行命令或者定期地執行。
  • static ScheduledExecutorService newSingleThreadScheduledExecutor() :創建一個單線程執行程序,它可安排在給定延遲後運行命令或者定期地執行。
    ThreadFactory是一個接口,該接口允許允許應用程序使用特殊的線程子類、屬性等,使用線程工廠就無需再手工編寫對 new Thread 的調用,它根據需要創建新線程的對象。如下面的代碼是一個簡單的線程工廠,該工廠根據傳進來的Runnable對象創建後臺線程。
class SimpleThreadFactory implements ThreadFactory {
   public Thread newThread(Runnable r) { //需要要實現的方法
     Thread t = new Thread(r);
     t.setDaemon(true);
     return t;
   }
 }
    可通過下面的方法向ExecutorService提交要執行的任務和關閉任務:
  • Future<T> submit(Callable<T> task):提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future;
  • Future<?> submit(Runnable task):提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future;結束後返回null;
  • <T> Future<T> submit(Runnable task, T result):提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在成功完成時將會返回給定的結果T;
  • void execute(Runnable command):在未來某個時間執行給定的命令。該命令可能在新的線程、已入池的線程或者正調用的線程中執行,這由 Executor 實現決定
  • void shutdown():啓動一次順序關閉,執行以前提交的任務,但不接受新任務。如果已經關閉,則調用沒有其他作用。
  • List<Runnable> shutdownNow():試圖停止所有正在執行的活動任務,暫停處理正在等待的任務,並返回等待執行的任務列表,該方法其實是發送interrupt()調用給它啓動的所有線程;
    使用ScheduledExecutorService,該接口可以在指定延遲後或週期性地執行線程任務的線程池,爲ExecutorService接口的子接口,提供以下的方法:
  • <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit):創建並執行在給定延遲後啓用的ScheduledFuture;
  • ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) :創建並執行在給定延遲後啓用的一次性操作,在delay後執行
  • ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):創建並執行一個在給定初始延遲後首次啓用的定期操作,後續操作具有給定的週期;也就是將在 initialDelay 後開始執行,然後在 initialDelay+period 後執行,接着在 initialDelay + 2 * period 後執行,依此類推;
  • ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) :創建並執行一個在給定初始延遲後首次啓用的定期操作,隨後,在每一次執行終止和下一次執行開始之間都存在給定的延遲
4.線程中斷
    Thread.interrupt()方法不會中斷一個正在運行的線程。這一方法實際上完成的是,在線程受到阻塞或者正在嘗試阻塞時拋出一箇中斷信號,這樣線程就得以退出阻塞的狀態。更確切的說,如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,那麼,它將接收到一箇中斷異常(InterruptedException),從而提早地終結被阻塞狀態。當拋出異常或者調用Thread.interrupted()時,中斷狀態將被複位。所以,只有在Object.wait, Thread.join和Thread.sleep這三個方法上已經阻塞或者嘗試阻塞的線程,當中斷位被設置時,纔會拋出異常,中斷狀態被清除,否則中斷不會真正中斷線程的執行。I/O和在synchronized塊上的等待是不可中斷的,可以通過關閉任務在其上發生阻塞的底層資源來中斷。
5.捕獲線程異常
    異常不能跨線程傳播,因此其他線程中拋出的異常不會傳播到Main線程。Thread.UncaughtExceptionHandler接口允許在每個Thread對象上附着一個異常處理器。該接口中的方法聲明爲:public void uncaughtException(Thread t, Throwable e);對線程對象調用setUncaughtExceptionHandler()方法可以爲線程設置異常處理器。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章