簡單了解啟動線程的幾種方式:
1. 實作Runnable接口建立一個任務, 調用myTask.run()方法來啟動它

2, 建構Thread對象, 調用thread.start()方法啟動
這裡可以看到, 我們給Thread構造器傳入了runable對象
細心的小夥伴看到這裡可能會有疑惑, 我們知道Thread同樣有run方法, 這裡為什麼要調用thread.start()而不是thread.run()呢 ?
這裡的target就是我們傳進去的runable對象,是以thread的run方法裡也是執行了runable的run方法
再看下start方法, 我這裡看到的是android-30的源碼,可以看到Android在這裡做了一些修改
注釋裡這段英文的意思是說:
調用該方法來啟動一個線程時, java VM會去call run方法
調用該方法後會有兩個線程同時運作(主線程執行完 start()後傳回,調用run方法後子線程也開始執行)
多次啟動一個線程是非法的
特别是, 如果一個線程被執行完成, 它将不能再被啟動
是以, 回答上面那個問題, 為什麼調用start來啟動線程而不是直接調用run呢?
因為start方法中 1), 會判斷目前線程的狀态,如果已經被啟動, 則會抛出 IllegalThreadStateException
2), 會将該線程加到 一個group裡, 這個group可能包含了目前線程的多個執行個體。加到這裡有什麼好處呢?。。。。,,等我知道了再來寫
3, 通過Executor來管理線程
CachedThreadPool
FixedThreadPool建立固定數量的線程池
SingleThreadExecutor
這裡我們建立了3個線程(id分别為0,1,2),并使用singleThreadExecutor來啟動它, 看下運作結果
我們看到: 1), 線程是嚴格按照我們期望的順序去啟動的(0--> 1 --> 2)。 我們知道在多線程中, 線程間的排程是由線程排程器來完成的, 排程過程可以說是不确定的, 但是SingleThreadExecutor會按照線程被送出的順序去執行。是以我們說SingleThreadExecutor會序列化所有送出給它的任務,并且維護它自己的懸挂任務隊列。
2), 第一個線程執行完成之後才去執行下一個
是以,如果我們有幾個線程需要通路同一個系統資源時, 使用這種方式可以確定在任何時刻都隻有唯一的線程在操作資料, 進而實作同步,而且線程執行的順序還是可控的。
4, 通過Callable接口建立線程
在上文中, 我們嘗試了通過實作Runnable接口來建立線程。 但是它并不會傳回任何值。
那麼如果我們希望在任務完成時有傳回值, 就可以實作Callable接口。 實作callable接口需要重寫call方法, call方法的傳回值就是該任務的傳回
需要特别注意的是, 我們必須使用ExecutorService.submit()方法來啟動它
看下運作結果:
5, 繼承Thread類建立線程
小結--建立/啟動線程的方式:
1)讓我們的task實作runnable接口, 重寫run方法, 使用mytask.run()啟動
2)讓我們的task實作runnable接口,重寫run方法, 使用ExecutorService.execute(runnable)方式啟動。 常用的ExecutorService有 CachedThreadPool, FixedThreadPool 和 SingleThreadExecutor
3)在Thread的構造方法中傳入runnable對象, 使用thread.start()方式啟動 (start方法本質上還是去調用了run方法, 但是在調用之前多了一些檢查的工作)
4)讓我們的task繼承自Thread, 重寫run()方法, 使用thread.start()方式啟動
5)讓我們的task實作Callable接口, 使用ExecutorService.submit()方式啟動。 該方法可以在任務執行完後給我們傳回值
其中1,2,3可以歸為同類, 因為都是實作了runnable接口