一、Java 線程實現(xiàn)/創(chuàng)建方式
注意:
? 新建的線程不會自動開始運行,必須通過start( )方法啟動
? 不能直接調(diào)用run()來啟動線程,這樣run()將作為一個普通方法立即執(zhí)行,執(zhí)行完畢前其他線程無法并發(fā)執(zhí)行
? Java程序啟動時,會立刻創(chuàng)建主線程,main就是在這個線程上運行。當不再產(chǎn)生新線程時,程序是單線程的
1.1 繼承Thread 類
Thread 類本質上是實現(xiàn)了 Runnable 接口的一個實例,代表一個線程的實例。啟動線程的唯一方法就是通過 Thread 類的 start()實例方法。start()方法是一個 native 方法,它將啟動一個新線程,并執(zhí)行 run()方法。
? 優(yōu)勢:編寫簡單
? 劣勢:無法繼承其它父類
1.1.1 ****創(chuàng)建:繼承Thread+重寫run
1.1.2 啟動:創(chuàng)建子類對象+調(diào)用start
public class StartThread extends Thread{
//線程入口點
@Override
public void run() {
for(int i=0;i<10;i++) {
System.out.println("listen music");
}
}
public static void main(String[] args) {
//創(chuàng)建子類對象
StartThread st=new StartThread();
//調(diào)用start方法
st.start();//開啟新線程交于cpu決定執(zhí)行順序
for(int i=0;i<10;i++) {
System.out.println("coding");
}
}
}
1.2 實現(xiàn)runnable接口
如果自己的類已經(jīng) extends 另一個類,就無法直接 extends Thread,此時,可以實現(xiàn)一個Runnable 接口。
? 優(yōu)勢:可以繼承其它類,多線程可共享同一個Runnable對象
? 劣勢:編程方式稍微復雜,如果需要訪問當前線程,需要調(diào)用Thread.currentThread()方法
1.2.1 創(chuàng)建:實現(xiàn)runnable接口+重寫run
1.2.2 啟動:創(chuàng)建實現(xiàn)類對象+Thread類對象+調(diào)用start
public class StartRun implements Runnable{
//線程入口點
@Override
public void run() {
for(int i=0;i<10;i++) {
System.out.println("listen music");
}
}
public static void main(String[] args) {
//創(chuàng)建實現(xiàn)類對象
StartRun st=``new` `StartRun();
//創(chuàng)建代理類對象<br>
//啟動 MyThread,需要首先實例化一個 Thread,并傳入自己的 MyThread 實例:`
Thread t=``new` `Thread(st);
//事實上,當傳入一個 Runnable target 參數(shù)給 Thread 后,Thread 的 run()方法就會調(diào)用target.run()
//調(diào)用start方法
t.start();//開啟新線程交于cpu決定執(zhí)行順序`
//匿名法
// new Thread(new StartRun()).start();
for(int i=0;i<10;i++) {
System.out.println("coding");
}
}
}
1.3 實現(xiàn)Callable接口
有返回值的任務必須實現(xiàn) Callable 接口,類似的,無返回值的任務必須 Runnable 接口。執(zhí)行Callable 任務后,可以獲取一個 Future 的對象,在該對象上調(diào)用 get 就可以獲取到 Callable 任務返回的 Object 了,再結合線程池接口 ExecutorService 就可以實現(xiàn)傳說中有返回結果的多線程了。
? 與實行Runnable相比, Callable功能更強大些
? 方法不同
? 可以有返回值,支持泛型的返回值
? 可以拋出異常
? 需要借助FutureTask,比如獲取返回結果
Future接口
? 可以對具體Runnable、Callable任務的執(zhí)行結果進行取消、查詢是否完成、獲取結果等。
? FutrueTask是Futrue接口的唯一的實現(xiàn)類
? FutureTask 同時實現(xiàn)了Runnable, Future接口。它既可以作為Runnable被線程執(zhí)行,又可以作為Future得到Callable的返回值
//創(chuàng)建一個線程池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
// 創(chuàng)建多個有返回值的任務`
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < taskSize; i++) {
Callable c = ``new` `MyCallable(i +" ");
// 執(zhí)行任務并獲取 Future 對象
Future f = pool.submit(c);
list.add(f);
}
// 關閉線程池
pool.shutdown();
// 獲取所有并發(fā)任務的運行結果`
for (Future f : list) {
// 從 Future 對象上獲取任務的返回值,并輸出到控制臺
System.out.println(``"res:"` `+ f.get().toString());
}
1.4 基于線程池的方式
線程和數(shù)據(jù)庫連接這些資源都是非常寶貴的資源。那么每次需要的時候創(chuàng)建,不需要的時候銷毀,是非常浪費資源的。那么我們就可以使用緩存的策略,也就是使用線程池。
// 創(chuàng)建線程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
while(true) {
threadPool.execute(new Runnable() { // 提交多個線程任務,并執(zhí)行
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is running ..");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
} `
二、四種線程池
Java 里面線程池的頂級接口是 Executor,但是嚴格意義上講 Executor 并不是一個線程池,而只是一個執(zhí)行線程的工具。真正的線程池接口是 ExecutorService。

2.1 newCachedThreadPool
創(chuàng)建一個可根據(jù)需要創(chuàng)建新線程的線程池,但是在以前構造的線程可用時將重用它們。對于執(zhí)行很多短期異步任務的程序而言,這些線程池通??商岣叱绦蛐阅堋?strong>調(diào)用 execute 將重用以前構造的線程(如果線程可用)。如果現(xiàn)有線程沒有可用的,則創(chuàng)建一個新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。因此,長時間保持空閑的線程池不會使用任何資源。
2.2 newFixedThreadPool
創(chuàng)建一個可重用固定線程數(shù)的線程池,以共享的無界隊列方式來運行這些線程。在任意點,在大多數(shù) Threads 線程會處于處理任務的活動狀態(tài)。如果在所有線程處于活動狀態(tài)時提交附加任務,則在有可用線程之前,附加任務將在隊列中等待。如果在關閉前的執(zhí)行期間由于失敗而導致任何線程終止,那么一個新線程將代替它執(zhí)行后續(xù)的任務(如果需要)。在某個線程被顯式地關閉之前,池中的線程將一直存在。
2.3 newScheduledThreadPool
創(chuàng)建一個線程池,它可安排在給定延遲后運行命令或者定期地執(zhí)行。
ScheduledExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(3);
scheduledThreadPool.schedule(newRunnable(){
@Override
public void run() {
System.out.println("延遲三秒");
}
}, 3, TimeUnit.SECONDS);
scheduledThreadPool.scheduleAtFixedRate(newRunnable(){
@Override
public void run() {
System.out.println延遲 1 秒后每三秒執(zhí)行一次");
},1,3,TimeUnit.SECONDS);
2.4 newSingleThreadExecutor
Executors.newSingleThreadExecutor()返回一個線程池(這個線程池只有一個線程),這個線程池可以在線程死后(或發(fā)生異常時)重新啟動一個線程來替代原來的線程繼續(xù)執(zhí)行下去!