1線程的創(chuàng)建方式
1.1直接繼承Thread
class MyThread extends Thread {
@Override
public void run() {
super.run();
}
}
1.2實現(xiàn)Runble接口
class MyRunble implements Runnable{
@Override
public void run() {
}
}
1.3實現(xiàn)Callable接口(這種方式嚴(yán)格意義上來說 并不是一種實現(xiàn)方式 本質(zhì)上是Runnable的實現(xiàn)方式)
class MyCallable extends Callable<String>{
@Override
public String call() throws Exception {
return "返回值";
}
}
1.4對應(yīng)的調(diào)用方式
public static void main(String[] args){
//方式一
MyThread myThread = new MyThread();
myThread.start();
//方式二
new Thread(new MyRunble()).start();
//方式三(FutureTask最終派生自Runnable)
FutureTask<String> futureTask = new FutureTask<String>(new MyCallable());
new Thread(futureTask).start();
futureTask.get();//獲取返回值
}
1.4不同創(chuàng)建方式的區(qū)別
采用繼承Thread類方式:
〕绨堋(1)優(yōu)點:編寫簡單,如果需要訪問當(dāng)前線程七咧,無需使用Thread.currentThread()方法栅隐,直接使用this邦尊,即可獲得當(dāng)前線程卑雁。
】蕖(2)缺點:因為線程類已經(jīng)繼承了Thread類异雁,所以不能再繼承其他的父類。
采用實現(xiàn)Runnable接口方式:
∈枪怼(1)優(yōu)點:線程類只是實現(xiàn)了Runable接口肤舞,還可以繼承其他的類。在這種方式下均蜜,可以多個線程共享同一個目標(biāo)對象李剖,所以非常適合多個相同線程來處理同一份資源的情況,從而可以將CPU代碼和數(shù)據(jù)分開囤耳,形成清晰的模型篙顺,較好地體現(xiàn)了面向?qū)ο蟮乃枷搿?br>
∨忌帧(2)缺點:編程稍微復(fù)雜,如果需要訪問當(dāng)前線程慰安,必須使用Thread.currentThread()方法腋寨。
Runnable和Callable的區(qū)別:
(1)Callable規(guī)定的方法是call(),Runnable規(guī)定的方法是run().
(2)Callable的任務(wù)執(zhí)行后可返回值,而Runnable的任務(wù)是不能返回值得
(3)call方法可以拋出異常化焕,run方法不可以萄窜,因為run方法本身沒有拋出異常,所以自定義的線程類在重寫run的時候也無法拋出異常
(4)運行Callable任務(wù)可以拿到一個Future對象撒桨,表示異步計算的結(jié)果查刻。它提供了檢查計算是否完成的方法,以等待計算的完成凤类,并檢索計算的結(jié)果穗泵。通過Future對象可以了解任務(wù)執(zhí)行情況,可取消任務(wù)的執(zhí)行谜疤,還可獲取執(zhí)行結(jié)果佃延。
start()和run()的區(qū)別
start()方法用來,開啟線程夷磕,但是線程開啟后并沒有立即執(zhí)行履肃,他需要獲取cpu的執(zhí)行權(quán)才可以執(zhí)行
run()方法是由jvm創(chuàng)建完本地操作系統(tǒng)級線程后回調(diào)的方法,不可以手動調(diào)用(否則就是普通方法)
2線程的停止方式
2.1stop()
暴力的停止坐桩,會造成危險和問題尺棋,不可使用,不詳細(xì)介紹绵跷。
interrupt()
目前最優(yōu)的辦法膘螟,目的是為了完成run方法的運行。
調(diào)用interrupt()方法分為兩種情況碾局,當(dāng)前線程是否調(diào)用了sleep荆残,不同的情況,處理方式不一樣净当。
2.2.1未調(diào)用
static class MyThread extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()){
System.out.println("MyThread run");
}
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//方式一
MyThread myThread = new MyThread();
myThread.start();
Thread.sleep(2);
//發(fā)射終止信號
myThread.interrupt();
}
運行截圖:
這種方式就是改變isInterrupted的值脊阴,從而達(dá)到退出循環(huán)的目的,當(dāng)然我們可以根據(jù)自己的實際情況來加入判斷蚯瞧,從而完成run方法的運行,達(dá)到停止線程的目的品擎。
isInterrupted是系統(tǒng)提供的埋合,默認(rèn)值是false所以我們在判斷的時候要加上!。當(dāng)我們調(diào)用interrupt()方法后萄传,isInterrupted會被置為true甚颂。
2.2.1調(diào)用
static class MyThread extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()){
System.out.println("MyThread run");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
我們在之前代碼的基礎(chǔ)上加了sleep方法蜜猾,這時我們發(fā)現(xiàn),循環(huán)不能被停止了(調(diào)用代碼不變)振诬。
為什么我們只是讓線程睡一覺蹭睡,就不行了呢?
我們先看下sleep的源碼
public static native void sleep(long millis) throws InterruptedException;
通過源碼我們發(fā)現(xiàn)赶么,sleep方法會拋出一個InterruptedException異常肩豁。
當(dāng)我們調(diào)用interrupt()方法后,如果線程調(diào)用sleep方法辫呻,那么就會拋出InterruptedException異常清钥,而在拋出異常的時候,會清除中斷標(biāo)記放闺。所以當(dāng)循環(huán)進(jìn)行下一次循環(huán)的時候祟昭,還是會滿足條件,繼續(xù)執(zhí)行怖侦。
這里我們要注意的一點是篡悟,調(diào)用interrupt()方法后,調(diào)用sleep方法拋出異常的時候會清除中斷標(biāo)記匾寝,而wait不會搬葬。
要注意的是,如果我們沒有調(diào)用interrupt()方法旗吁,調(diào)用sleep()方法的時候踩萎,是不會拋出異常的,這點我覺得很重要很钓,因為這點我苦惱了半天香府,后來自己跑了幾遍代碼才發(fā)現(xiàn)是這么回事。
綜上所述码倦,我們得知了調(diào)用sleep()方法時會拋出InterruptedException異常企孩,并且會清除中斷標(biāo)記,那么我們就可以在異常捕獲階段進(jìn)行處理了袁稽。
static class MyThread extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()){
System.out.println("MyThread run");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
//根據(jù)自己的需要 再將isInterrupted置為true
interrupt();
e.printStackTrace();
//根據(jù)當(dāng)前代碼邏輯 我們可以直接終止循環(huán)
break;
}
}
}
}
2.1守護(hù)線程
我們也可以通過setDaemon()方法將線程設(shè)為守護(hù)線程勿璃,這樣當(dāng)被守護(hù)的線程執(zhí)行完后,守護(hù)線程也就隨之而結(jié)束了推汽。
public static void main(String[] args) throws ExecutionException, InterruptedException {
//方式一
MyThread myThread = new MyThread();
myThread.setDaemon(true);
myThread.start();
Thread.sleep(1000);
// //發(fā)射終止信號
// myThread.interrupt();
}
上面的代碼也就是說myThread守護(hù)main線程 main線程結(jié)束 不管myThread是否結(jié)束 myThread都要結(jié)束补疑。
(誰調(diào)用的myThread,myThread就守護(hù)誰歹撒,main線程調(diào)用的莲组,myThread就守護(hù)main線程)