Java線程之Thread、Future、FutureTask源碼解析

目錄

1.Thread

1.1start方法源碼解析

1.2初始化源碼分析

2.Future

2.1基本架構

3.FutureTask

3.1整體架構

3.2初始化源碼解析

3.3get源碼解析


1.Thread


1.1start方法源碼解析

// 創建一個新的線程
public synchronized void start() {
    // 如果沒有初始化,拋異常
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    group.add(this);
    // started 是個標識符,我們在做一些事情的時候,經常這麼寫
    // 動作發生之前標識符是 false,發生完成之後變成 true
    boolean started = false;
    try {
        // 這裏會創建一個新的線程,線程狀態改變爲可執行狀態等待分配時間片
        start0();
        // 這裏執行的還是主線程
        started = true;
    } finally {
        try {
            // 如果失敗,把線程從線程組中刪除
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {}
    }
}
// 開啓新線程使用的是 native 方法
private native void start0();

先將該線程加入到線程組裏面,然後纔會使用start0方法將線程狀態改變爲可執行狀態等待cpu分配時間片

1.2初始化源碼分析

// 無參構造器,線程名字自動生成
public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}
// g 代表線程組,線程組可以對組內的線程進行批量的操作,比如批量的打斷 interrupt
// target 是我們要運行的對象
// name 我們可以自己傳,如果不傳默認是 "Thread-" + nextThreadNum(),
// stackSize 可以設置堆棧的大小
private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc) {
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }
    this.name = name.toCharArray();
    // 當前線程作爲父線程
    Thread parent = currentThread();// 初始化的線程會繼承當前線程
    this.group = g;// 繼承父線程的線程組
    this.daemon = parent.isDaemon();// 繼承父線程的守護屬性
    this.priority = parent.getPriority();// 繼承父線程的優先級
    // 繼承父線程的上下文類加載器
    // @啓動類加載器,@擴展類加載器,@應用程序類加載器,@自定義類加載器
    if (security == null || isCCLOverridden(parent.getClass()))
        this.contextClassLoader = parent.getContextClassLoader();
    else
        this.contextClassLoader = parent.contextClassLoader;
    // 繼承父線程訪問控制上下文權限
    this.inheritedAccessControlContext =
            acc != null ? acc : AccessController.getContext();
    this.target = target;// 設置Runnable接口
    setPriority(priority);// 設置優先級
    // 繼承父線程的inheritableThreadLocals值
    if (parent.inheritableThreadLocals != null)
        this.inheritableThreadLocals =
            ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    // 設置棧大小
    this.stackSize = stackSize;
    // 設置線程id
    tid = nextThreadID();
}

初始化線程,先將當前線程作爲父線程,然後繼承父線程的屬性(線程組,守護屬性,優先級,類加載器,訪問權限,ThreadLocal值),然後設置Runnable接口,設置優先級,設置棧大小,設置線程id


2.Future


2.1基本架構

  • 定義了異步計算框架,但是get獲取結果是阻塞的;

ps:異步只針對call/run方法的計算任務來說的,獲取結果依然是阻塞的

// 如果任務已經成功了,或已經取消了,是無法再取消的,會直接返回取消成功(true)
// 如果任務還沒有開始進行時,發起取消,是可以取消成功的。
// 如果取消時,任務已經在運行了,mayInterruptIfRunning 爲 true 的話,就可以打斷運行中的線程
// mayInterruptIfRunning 爲 false,表示不能打斷直接返回
boolean cancel(boolean mayInterruptIfRunning);// 取消任務

// 返回線程是否已經被取消了,true 表示已經被取消了
// 如果線程已經運行結束了,isCancelled 和 isDone 返回的都是 true
boolean isCancelled();// 是否已經取消
boolean isDone();// 是否已經運行結束了

// 等待結果返回
// 如果任務被取消了,拋 CancellationException 異常
// 如果等待過程中被打斷了,拋 InterruptedException 異常
V get() throws InterruptedException, ExecutionException;
// 等待,但是帶有超時時間的,如果超時時間外仍然沒有響應,拋 TimeoutException 異常
V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

該接口定義了任務取消,等待任務完成,判斷是否取消和是否完成方法


3.FutureTask


3.1整體架構

  • 實現了RunnableFuture接口適配器(Runnable和Future接口),並且組合了Callable接口
// 任務狀態
private volatile int state;
private static final int NEW          = 0;//線程任務創建
private static final int COMPLETING   = 1;//任務執行中
private static final int NORMAL       = 2;//任務執行結束
private static final int EXCEPTIONAL  = 3;//任務異常
private static final int CANCELLED    = 4;//任務取消成功
private static final int INTERRUPTING = 5;//任務正在被打斷中
private static final int INTERRUPTED  = 6;//任務被打斷成功
// 組合了 Callable 
private Callable<V> callable;
// 異步線程返回的結果
private Object outcome; 
// 當前任務所運行的線程
private volatile Thread runner;
// 記錄調用 get 方法時被等待的線程
private volatile WaitNode waiters;
  • FutureTask類整合了Runnable、Callable、Future三者的功能

3.2初始化源碼解析

// 使用 Callable 進行初始化
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    // 任務狀態初始化
    this.state = NEW;  
}
// 使用 Runnable 初始化,result一般爲null 。
public FutureTask(Runnable runnable, V result) {
    // 把 runnable 直接適配成了 callable。
    this.callable = Executors.callable(runnable, result);
    //初始化狀態
    this.state = NEW;
}
// 轉化 Runnable 成 Callable 的適配器類
static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

首先可以執行Callable方法,也可以執行Runnable方法

爲了統一簡化類的複雜性,將Runnable通過適配器模式變爲Callable

3.3get源碼解析

public V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException {
    if (unit == null)
        throw new NullPointerException();
    int s = state;
    // 如果任務已經在執行中了,並且等待一定的時間後,仍然在執行中,直接拋出異常
    if (s <= COMPLETING &&
        (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
        throw new TimeoutException();
    // 任務執行成功,返回執行的結果
    return report(s);
}

 

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