一蝶念、Java 線程實(shí)現(xiàn)/創(chuàng)建方式
注意:
? 新建的線程不會(huì)自動(dòng)開(kāi)始運(yùn)行劝贸,必須通過(guò)start( )方法啟動(dòng)
? 不能直接調(diào)用run()來(lái)啟動(dòng)線程,這樣run()將作為一個(gè)普通方法立即執(zhí)行挚躯,執(zhí)行完畢前其他線程無(wú)法并發(fā)執(zhí)行
? Java程序啟動(dòng)時(shí)锤岸,會(huì)立刻創(chuàng)建主線程集漾,main就是在這個(gè)線程上運(yùn)行。當(dāng)不再產(chǎn)生新線程時(shí)砸脊,程序是單線程的
1.1 繼承Thread 類
Thread 類本質(zhì)上是實(shí)現(xiàn)了 Runnable 接口的一個(gè)實(shí)例具篇,代表一個(gè)線程的實(shí)例。啟動(dòng)線程的唯一方法就是通過(guò) Thread 類的 start()實(shí)例方法凌埂。start()方法是一個(gè) native 方法驱显,它將啟動(dòng)一個(gè)新線程,并執(zhí)行 run()方法瞳抓。
? 優(yōu)勢(shì):編寫簡(jiǎn)單
? 劣勢(shì):無(wú)法繼承其它父類
1.1.1 ****創(chuàng)建:繼承Thread+重寫run
1.1.2 啟動(dòng):創(chuàng)建子類對(duì)象+調(diào)用start
public class StartThread extends Thread{
//線程入口點(diǎn)
@Override
public void run() {
for(int i=0;i<10;i++) {
System.out.println("listen music");
}
}
public static void main(String[] args) {
//創(chuàng)建子類對(duì)象
StartThread st=new StartThread();
//調(diào)用start方法
st.start();//開(kāi)啟新線程交于cpu決定執(zhí)行順序
for(int i=0;i<10;i++) {
System.out.println("coding");
}
}
}
1.2 實(shí)現(xiàn)runnable接口
如果自己的類已經(jīng) extends 另一個(gè)類埃疫,就無(wú)法直接 extends Thread,此時(shí)挨下,可以實(shí)現(xiàn)一個(gè)Runnable 接口熔恢。
? 優(yōu)勢(shì):可以繼承其它類脐湾,多線程可共享同一個(gè)Runnable對(duì)象
? 劣勢(shì):編程方式稍微復(fù)雜臭笆,如果需要訪問(wèn)當(dāng)前線程,需要調(diào)用Thread.currentThread()方法
1.2.1 創(chuàng)建:實(shí)現(xiàn)runnable接口+重寫run
1.2.2 啟動(dòng):創(chuàng)建實(shí)現(xiàn)類對(duì)象+Thread類對(duì)象+調(diào)用start
public class StartRun implements Runnable{
//線程入口點(diǎn)
@Override
public void run() {
for(int i=0;i<10;i++) {
System.out.println("listen music");
}
}
public static void main(String[] args) {
//創(chuàng)建實(shí)現(xiàn)類對(duì)象
StartRun st=``new` `StartRun();
//創(chuàng)建代理類對(duì)象<br>
//啟動(dòng) MyThread秤掌,需要首先實(shí)例化一個(gè) Thread愁铺,并傳入自己的 MyThread 實(shí)例:`
Thread t=``new` `Thread(st);
//事實(shí)上,當(dāng)傳入一個(gè) Runnable target 參數(shù)給 Thread 后闻鉴,Thread 的 run()方法就會(huì)調(diào)用target.run()
//調(diào)用start方法
t.start();//開(kāi)啟新線程交于cpu決定執(zhí)行順序`
//匿名法
// new Thread(new StartRun()).start();
for(int i=0;i<10;i++) {
System.out.println("coding");
}
}
}
1.3 實(shí)現(xiàn)Callable接口
有返回值的任務(wù)必須實(shí)現(xiàn) Callable 接口茵乱,類似的,無(wú)返回值的任務(wù)必須 Runnable 接口孟岛。執(zhí)行Callable 任務(wù)后瓶竭,可以獲取一個(gè) Future 的對(duì)象,在該對(duì)象上調(diào)用 get 就可以獲取到 Callable 任務(wù)返回的 Object 了渠羞,再結(jié)合線程池接口 ExecutorService 就可以實(shí)現(xiàn)傳說(shuō)中有返回結(jié)果的多線程了斤贰。
? 與實(shí)行Runnable相比, Callable功能更強(qiáng)大些
? 方法不同
? 可以有返回值次询,支持泛型的返回值
? 可以拋出異常
? 需要借助FutureTask荧恍,比如獲取返回結(jié)果
Future接口
? 可以對(duì)具體Runnable、Callable任務(wù)的執(zhí)行結(jié)果進(jìn)行取消屯吊、查詢是否完成送巡、獲取結(jié)果等。
? FutrueTask是Futrue接口的唯一的實(shí)現(xiàn)類
? FutureTask 同時(shí)實(shí)現(xiàn)了Runnable, Future接口盒卸。它既可以作為Runnable被線程執(zhí)行骗爆,又可以作為Future得到Callable的返回值
//創(chuàng)建一個(gè)線程池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
// 創(chuàng)建多個(gè)有返回值的任務(wù)`
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < taskSize; i++) {
Callable c = ``new` `MyCallable(i +" ");
// 執(zhí)行任務(wù)并獲取 Future 對(duì)象
Future f = pool.submit(c);
list.add(f);
}
// 關(guān)閉線程池
pool.shutdown();
// 獲取所有并發(fā)任務(wù)的運(yùn)行結(jié)果`
for (Future f : list) {
// 從 Future 對(duì)象上獲取任務(wù)的返回值,并輸出到控制臺(tái)
System.out.println(``"res:"` `+ f.get().toString());
}
1.4 基于線程池的方式
線程和數(shù)據(jù)庫(kù)連接這些資源都是非常寶貴的資源蔽介。那么每次需要的時(shí)候創(chuàng)建摘投,不需要的時(shí)候銷毀糟需,是非常浪費(fèi)資源的。那么我們就可以使用緩存的策略谷朝,也就是使用線程池洲押。
// 創(chuàng)建線程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
while(true) {
threadPool.execute(new Runnable() { // 提交多個(gè)線程任務(wù),并執(zhí)行
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is running ..");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
} `
二圆凰、四種線程池
Java 里面線程池的頂級(jí)接口是 Executor杈帐,但是嚴(yán)格意義上講 Executor 并不是一個(gè)線程池,而只是一個(gè)執(zhí)行線程的工具专钉。真正的線程池接口是 ExecutorService挑童。
2.1 newCachedThreadPool
創(chuàng)建一個(gè)可根據(jù)需要?jiǎng)?chuàng)建新線程的線程池,但是在以前構(gòu)造的線程可用時(shí)將重用它們跃须。對(duì)于執(zhí)行很多短期異步任務(wù)的程序而言站叼,這些線程池通常可提高程序性能菇民。調(diào)用 execute 將重用以前構(gòu)造的線程(如果線程可用)尽楔。如果現(xiàn)有線程沒(méi)有可用的,則創(chuàng)建一個(gè)新線程并添加到池中第练。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程阔馋。因此,長(zhǎng)時(shí)間保持空閑的線程池不會(huì)使用任何資源娇掏。
2.2 newFixedThreadPool
創(chuàng)建一個(gè)可重用固定線程數(shù)的線程池呕寝,以共享的無(wú)界隊(duì)列方式來(lái)運(yùn)行這些線程。在任意點(diǎn)婴梧,在大多數(shù) Threads 線程會(huì)處于處理任務(wù)的活動(dòng)狀態(tài)下梢。如果在所有線程處于活動(dòng)狀態(tài)時(shí)提交附加任務(wù),則在有可用線程之前塞蹭,附加任務(wù)將在隊(duì)列中等待孽江。如果在關(guān)閉前的執(zhí)行期間由于失敗而導(dǎo)致任何線程終止,那么一個(gè)新線程將代替它執(zhí)行后續(xù)的任務(wù)(如果需要)浮还。在某個(gè)線程被顯式地關(guān)閉之前竟坛,池中的線程將一直存在。
2.3 newScheduledThreadPool
創(chuàng)建一個(gè)線程池钧舌,它可安排在給定延遲后運(yùn)行命令或者定期地執(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()返回一個(gè)線程池(這個(gè)線程池只有一個(gè)線程),這個(gè)線程池可以在線程死后(或發(fā)生異常時(shí))重新啟動(dòng)一個(gè)線程來(lái)替代原來(lái)的線程繼續(xù)執(zhí)行下去!