Java知識(shí)總結(jié)-多線程的實(shí)現(xiàn)

一赃份、多線程的實(shí)現(xiàn)方式

編寫多線程程序一般有三種方法鸠姨,Thread,Runnable,Callable.

1).繼承Thread類

class MyThread extends Thread{  
  public MyThread(String name) {  
  }  
  public void run(){    
  }  
}  

2).實(shí)現(xiàn)Runnable接口

public interface Runnable {
    public abstract void run();
}

3).實(shí)現(xiàn)Callable接口

public interface Callable<V> {
    V call() throws Exception;
}

區(qū)別

  • Thread不適合于資源的共享
  • Thread類也是Runnable接口的子類铜秆。
  • Callable能返回執(zhí)行結(jié)果,Runnable不能返回結(jié)果讶迁;
  • Callable的call()方法允許拋出異常连茧,Runnable接口的run()方法的異常只能在內(nèi)部消化,不能繼續(xù)上拋巍糯;

Callable接口支持返回執(zhí)行結(jié)果啸驯,此時(shí)需要調(diào)用FutureTask.get()方法實(shí)現(xiàn),此方法會(huì)阻塞主線程直到獲取‘將來(lái)’結(jié)果鳞贷;當(dāng)不調(diào)用此方法時(shí)坯汤,主線程不會(huì)阻塞!


import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ExecutorsTester {

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
//        executorService.execute(new ThreadForpools(1));

        int a = 1, b = 100;
        Future<Integer> future = executorService.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println( " 開始處理線程2罄ⅰ6枘簟!");
                Thread.sleep(3000);

                return a+b;
            }
        });
        System.out.println(future.isDone());
        System.out.println(future.isCancelled());

        while (! future.isDone()) {
            System.out.println("still waiting....");
            Thread.sleep(1000 * 1);
//            System.out.println("OK");
        }
        Integer obj = future.get();
        System.out.println(obj);

        executorService.shutdown();
    }

}

二咱筛、線程的狀態(tài)

  • 創(chuàng)建(new)狀態(tài): 準(zhǔn)備好了一個(gè)多線程的對(duì)象
  • 就緒(runnable)狀態(tài): 調(diào)用了start()方法, 等待CPU進(jìn)行調(diào)度
  • 運(yùn)行(running)狀態(tài): 執(zhí)行run()方法
  • 阻塞(blocked)狀態(tài): 暫時(shí)停止執(zhí)行, 可能將資源交給其它線程使用
  • 終止(dead)狀態(tài): 線程銷毀

當(dāng)需要新起一個(gè)線程來(lái)執(zhí)行某個(gè)子任務(wù)時(shí)搓幌,就創(chuàng)建了一個(gè)線程。但是線程創(chuàng)建之后迅箩,不會(huì)立即進(jìn)入就緒狀態(tài)溉愁,因?yàn)榫€程的運(yùn)行需要一些條件(比如內(nèi)存資源),只有線程運(yùn)行需要的所有條件滿足了饲趋,才進(jìn)入就緒狀態(tài)拐揭。

當(dāng)線程進(jìn)入就緒狀態(tài)后撤蟆,不代表立刻就能獲取CPU執(zhí)行時(shí)間,也許此時(shí)CPU正在執(zhí)行其他的事情堂污,因此它要等待家肯。當(dāng)?shù)玫紺PU執(zhí)行時(shí)間之后,線程便真正進(jìn)入運(yùn)行狀態(tài)盟猖。

線程在運(yùn)行狀態(tài)過(guò)程中讨衣,可能有多個(gè)原因?qū)е庐?dāng)前線程不繼續(xù)運(yùn)行下去,比如用戶主動(dòng)讓線程睡眠(睡眠一定的時(shí)間之后再重新執(zhí)行)式镐、用戶主動(dòng)讓線程等待反镇,或者被同步塊給阻塞,此時(shí)就對(duì)應(yīng)著多個(gè)狀態(tài):time waiting(睡眠或等待一定的事件)娘汞、waiting(等待被喚醒)歹茶、blocked(阻塞)。

當(dāng)由于突然中斷或者子任務(wù)執(zhí)行完畢价说,線程就會(huì)被消亡辆亏。


1.jpg

blocked、waiting鳖目、time waiting又統(tǒng)稱為阻塞狀態(tài)

2.jpg

注:sleep和wait的區(qū)別:

  • sleep是Thread類的方法,wait是Object類中定義的方法.
  • Thread.sleep不會(huì)導(dǎo)致鎖行為的改變, 如果當(dāng)前線程是擁有鎖的, 那么Thread.sleep不會(huì)讓線程釋放鎖.
    Thread.sleep和Object.wait都會(huì)暫停當(dāng)前的線程. OS會(huì)將執(zhí)行時(shí)間分配給其它線程. 區(qū)別是, 調(diào)用wait后, 需要?jiǎng)e的線程執(zhí)行notify/notifyAll才能夠重新獲得CPU執(zhí)行時(shí)間.

線程的sleep()方法和yield()方法有什么區(qū)別?

  • ① sleep()方法給其他線程運(yùn)行機(jī)會(huì)時(shí)不考慮線程的優(yōu)先級(jí)缤弦,因此會(huì)給低優(yōu)先級(jí)的線程以運(yùn)行的機(jī)會(huì)领迈;yield()方法只會(huì)給相同優(yōu)先級(jí)或更高優(yōu)先級(jí)的線程以運(yùn)行的機(jī)會(huì);
  • ② 線程執(zhí)行sleep()方法后轉(zhuǎn)入阻塞(blocked)狀態(tài)碍沐,而執(zhí)行yield()方法后轉(zhuǎn)入就緒(ready)狀態(tài)狸捅;
  • ③ sleep()方法聲明拋出InterruptedException,而yield()方法沒(méi)有聲明任何異常累提;
  • ④ sleep()方法比yield()方法(跟操作系統(tǒng)CPU調(diào)度相關(guān))具有更好的可移植性尘喝。

請(qǐng)說(shuō)出與線程同步以及線程調(diào)度相關(guān)的方法。

wait():使一個(gè)線程處于等待(阻塞)狀態(tài)斋陪,并且釋放所持有的對(duì)象的鎖朽褪;
sleep():使一個(gè)正在運(yùn)行的線程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法无虚,調(diào)用此方法要處理InterruptedException異常缔赠;
notify():?jiǎn)拘岩粋€(gè)處于等待狀態(tài)的線程,當(dāng)然在調(diào)用此方法的時(shí)候友题,并不能確切的喚醒某一個(gè)等待狀態(tài)的線程嗤堰,而是由JVM確定喚醒哪個(gè)線程,而且與優(yōu)先級(jí)無(wú)關(guān)度宦;
notityAll():?jiǎn)拘阉刑幱诘却隣顟B(tài)的線程踢匣,該方法并不是將對(duì)象的鎖給所有線程告匠,而是讓它們競(jìng)爭(zhēng),只有獲得鎖的線程才能進(jìn)入就緒狀態(tài)离唬;

守護(hù)線程(Daemon Thread)和用戶線程(User Thread)的區(qū)別

Daemon的作用是為其他線程的運(yùn)行提供服務(wù)后专,比如說(shuō)GC線程。其實(shí)User Thread線程和Daemon Thread守護(hù)線程本質(zhì)上來(lái)說(shuō)去沒(méi)啥區(qū)別的男娄,唯一的區(qū)別之處就在虛擬機(jī)的離開:如果User Thread全部撤離行贪,那么Daemon Thread也就沒(méi)啥線程好服務(wù)的了,所以虛擬機(jī)也就退出了模闲。

守護(hù)線程依賴于創(chuàng)建它的線程建瘫,而用戶線程則不依賴。舉個(gè)簡(jiǎn)單的例子:如果在main線程中創(chuàng)建了一個(gè)守護(hù)線程尸折,當(dāng)main方法運(yùn)行完畢之后啰脚,守護(hù)線程也會(huì)隨著消亡。而用戶線程則不會(huì)实夹,用戶線程會(huì)一直運(yùn)行直到其運(yùn)行完畢橄浓。在JVM中,像垃圾收集器線程就是守護(hù)線程亮航。

三荸实、線程的優(yōu)先級(jí)

在操作系統(tǒng)中,線程可以劃分優(yōu)先級(jí)缴淋,優(yōu)先級(jí)較高的線程得到的CPU資源較多准给,也就是CPU優(yōu)先執(zhí)行優(yōu)先級(jí)較高的線程對(duì)象中的任務(wù)。
設(shè)置線程優(yōu)先級(jí)有助于幫“線程規(guī)劃器”確定在下一次選擇哪一個(gè)線程來(lái)優(yōu)先執(zhí)行重抖。
設(shè)置線程的優(yōu)先級(jí)使用setPriority()方法露氮,此方法在JDK的源碼如下:

public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

在Java中,線程的優(yōu)先級(jí)分為1~10這10個(gè)等級(jí)钟沛,如果小于1或大于10畔规,則JDK拋出異常throw new IllegalArgumentException()。

線程優(yōu)先級(jí)特性:

  • 繼承性:
    比如A線程啟動(dòng)B線程恨统,則B線程的優(yōu)先級(jí)與A是一樣的叁扫。
  • 規(guī)則性:
    高優(yōu)先級(jí)的線程總是大部分先執(zhí)行完,但不代表高優(yōu)先級(jí)線程全部先執(zhí)行完延欠。
  • 隨機(jī)性:
    優(yōu)先級(jí)較高的線程不一定每一次都先執(zhí)行完陌兑。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市由捎,隨后出現(xiàn)的幾起案子兔综,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件软驰,死亡現(xiàn)場(chǎng)離奇詭異涧窒,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)锭亏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門纠吴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人慧瘤,你說(shuō)我怎么就攤上這事戴已。” “怎么了锅减?”我有些...
    開封第一講書人閱讀 169,631評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵糖儡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我怔匣,道長(zhǎng)握联,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,199評(píng)論 1 300
  • 正文 為了忘掉前任每瞒,我火速辦了婚禮金闽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘剿骨。我一直安慰自己代芜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評(píng)論 6 398
  • 文/花漫 我一把揭開白布浓利。 她就那樣靜靜地躺著蜒犯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荞膘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,793評(píng)論 1 314
  • 那天玉工,我揣著相機(jī)與錄音羽资,去河邊找鬼。 笑死遵班,一個(gè)胖子當(dāng)著我的面吹牛屠升,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狭郑,決...
    沈念sama閱讀 41,221評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼腹暖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了翰萨?” 一聲冷哼從身側(cè)響起脏答,我...
    開封第一講書人閱讀 40,174評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后殖告,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阿蝶,經(jīng)...
    沈念sama閱讀 46,699評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評(píng)論 3 343
  • 正文 我和宋清朗相戀三年黄绩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了羡洁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,918評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爽丹,死狀恐怖筑煮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粤蝎,我是刑警寧澤真仲,帶...
    沈念sama閱讀 36,573評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站诽里,受9級(jí)特大地震影響袒餐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谤狡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評(píng)論 3 336
  • 文/蒙蒙 一灸眼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧墓懂,春花似錦焰宣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至榜跌,卻和暖如春闪唆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钓葫。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工悄蕾, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人础浮。 一個(gè)月前我還...
    沈念sama閱讀 49,364評(píng)論 3 379
  • 正文 我出身青樓帆调,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親豆同。 傳聞我的和親對(duì)象是個(gè)殘疾皇子番刊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容