01-多線程

Java多線程

線程和進程的區(qū)別

  • 本質(zhì):由CPU進行調(diào)度的\color{red}{并發(fā)式}執(zhí)行任務(wù)昌犹,多個任務(wù)被快速輪換執(zhí)行蒜危,使得宏觀上具有多個線程或者進程同時執(zhí)行的效果她君。
  • 進程\color{blue}{系統(tǒng)進行資源分配和調(diào)度的一個獨立單位},也是擁有系統(tǒng)資源的基本單位放椰。進程是系統(tǒng)中獨立存在的實體,它可以擁有自己獨立的資源愉粤,擁有自己私有的地址空間砾医,進程之間不能直接訪問其他進程的地址空間。
  • 線程:線程是CPU調(diào)度的基本單位衣厘,也就是說在一個進程中可以有多個并發(fā)程序執(zhí)行流如蚜,線程拓展了進程的概念,使得任務(wù)的執(zhí)行得到更加的細分影暴,所以Thread有時候也被稱為Lightweight Process错邦。
    \color{red}{線程是進程的執(zhí)行單元,但是線程不是分配系統(tǒng)資源的單位}型宙,它們共享所在進程的資源兴猩,包括共享內(nèi)存,公有數(shù)據(jù)早歇,全局變量倾芝,進程文件描述符,進程處理器箭跳,進程代碼段晨另,進程用戶ID等等,線程獨立擁有自己的線程ID谱姓,堆棧借尿,程序計數(shù)器,局部變量屉来,寄存器組值路翻,優(yōu)先級,信號屏蔽碼茄靠,錯誤返回碼等等茂契,。\color{red}{線程是獨立運行的慨绳,其執(zhí)行是搶占式的掉冶,線程共享進程資源} 真竖,線程之間的通信要進程之間的通信來得容易得多。此外厌小,線程的創(chuàng)建和銷毀的開銷也遠遠小于進程的系統(tǒng)開銷恢共。

線程和線程池

  • 線程池:雖然線程的創(chuàng)建銷毀的開銷相對較小,但是頻繁得創(chuàng)建和銷毀也會消耗有限的資源璧亚,從而帶來性能上的浪費讨韭,也不夠高效。因此線程池的出癣蟋,現(xiàn)就是為了解決這一問題拐袜,\color{red}{即在初始狀態(tài)創(chuàng)建并維護一定數(shù)量的空閑線程},當(dāng)有需要執(zhí)行的任務(wù)梢薪,就交付給線程中的一個線程蹬铺,任務(wù)執(zhí)行結(jié)束后,該線程也不會死亡秉撇,而是回到線程池中重新變?yōu)榭臻e狀態(tài)甜攀。

線程創(chuàng)建的三種方法

1.繼承Thread創(chuàng)建多線程

此時每次創(chuàng)建的Thread對象并不能共享線程類的實例變量,也就是下面程序中的i琐馆。

public class FirstThread extends Thread{
    private int i;
    @Override
    public void run() {
        for(i=0;i<10;i++) 
            System.out.println(getName()); // 繼承自Thread 
    }
    
    public static void main(String[] args) {    
        new FirstThread().start();
        new FirstThread().start(); // 注意啟動線程需要用Start
    }
}

2.實現(xiàn)Runnable接口創(chuàng)建線程類

Runnable接口是一個函數(shù)式接口(可以使用Lambda表達式)规阀,通常做法是重寫接口中的run方法,此時方法體即為線程執(zhí)行體瘦麸,使用Runnable接口實現(xiàn)類的實例作為Thread的target來創(chuàng)建Thread對象,此時因為使用一個共同的target線程執(zhí)行體谁撼,多個線程可以共享一個實例變量。

public class SecondThread implements Runnable{
    private int i;
    @Override
    public void run() {
        for(;i<10;i++) {
            System.out.println(Thread.currentThread().getName() + " "+ i);
        }
    }
    
    public static void main(String[] args) {
        SecondThread targetRunnable = new SecondThread();
        new Thread(targetRunnable,"線程1").start();
        new Thread(targetRunnable).start();
    }
}

3.使用Callable和Future創(chuàng)建線程

Callable類似于Runnable滋饲,提供一個Call()方法作為線程執(zhí)行體厉碟,并且可以有返回值,以及拋出異常屠缭,那么我們?nèi)绾文玫椒祷刂倒抗模琷ava提供了future接口,在接口里定義了一些公共方法來控制關(guān)聯(lián)它的Callable任務(wù)呵曹,然后java還貼心的給了FutureTask類款咖,該類實現(xiàn)了Future接口和Runnable接口,所以FutureTask的實例就可以作為Thread的Target奄喂,所以通常做法是創(chuàng)建Callable接口實現(xiàn)類铐殃,并對該實現(xiàn)類的實例使用FutureTask來包裝。

public class ThridThread {
    public static void main(String[] args) {        
        // lambda 表達式 + functionInterface 類型轉(zhuǎn)換
        // Callbable: 有返回值
        FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)()->{
            int i =0;
            for(;i<100;i++) {
                System.out.println(Thread.currentThread().getName() + " "+ i);
            }
            return i;
    }); 
        new Thread(task,"有返回值的線程").start();
        try {
            System.out.println("子線程的返回值"+task.get());
        }catch(Exception e) {
            e.printStackTrace();
        }
 }
}

線程的生命周期

image.png

image.png

線程控制

1.join()線程

讓一個線程等待另一個線程跨新,當(dāng)在某個線程執(zhí)行流中調(diào)用其他線程的join()方法富腊,該線程將被阻塞,知道join線程執(zhí)行完畢為止玻蝌。

2.后臺線程

后臺線程又稱為\color{red}{Daemon Thread}蟹肘,守護線程词疼,JVM的垃圾回收線程就是典型的后臺線程俯树。特征是:\color{red}{如果所有前臺線程都死亡帘腹,那么后臺線程自動死亡}。調(diào)用Thread對象的setDaemon(true)可以將指定線程設(shè)置為后臺線程许饿,注意\color{red}{需要在Start()之前調(diào)用阳欲,主線程默認為前臺線程,}
\color{red}{前臺線程創(chuàng)建的子線程默認為前臺線程陋率,后臺線程創(chuàng)建的子線程默認為后臺線程球化。}

3.yield():線程讓步

Thread的靜態(tài)方法,使得正在執(zhí)行的線程暫停瓦糟,但不會阻塞線程筒愚,只是交出CPU的控制權(quán),將線程轉(zhuǎn)為就緒狀態(tài)菩浙,讓系統(tǒng)調(diào)度器重新調(diào)度一次巢掺。當(dāng)某個線程調(diào)用yield方法暫停后,只有優(yōu)先級與當(dāng)前線程相同劲蜻,或者優(yōu)先級比當(dāng)前線程更高的線程才有可能獲得執(zhí)行機會陆淀。

4.setPriority(int newPriority)

改變線程優(yōu)先級,高優(yōu)先級的線程能獲得更多的執(zhí)行機會先嬉。

線程同步

線程的同步的意義在于線程安全轧苫,也就是說有多個線程并發(fā)訪問同一個對象,而線程調(diào)度的不確定性可能帶來潛在的安全問題

同步方法塊:顯式指定同步監(jiān)視器

public class DrawThread extends Thread {
    private Account account;
    private double drawaccout;
    
    public DrawThread(String name,Account account,double drawaccount) {
        super(name)疫蔓;
        this.account = account;
        this.drawaccout= drawaccount;
    }
    
    public void run() {
        synchronized(account) {
            if(account.getBlance()>=drawaccount) {
                System.out.println(getName()+"取錢成功");
                try {
                    Thread.sleep(1);
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

同步方法

  public synchronized void draw(double amount) {
        ……
    }

同步監(jiān)視器的釋放

  • break含懊,return等終止了代碼塊的執(zhí)行
  • 同步代碼塊或者方法中出現(xiàn)未處理的Error或者Exception,導(dǎo)致異常結(jié)束
  • 當(dāng)前線程執(zhí)行同步代碼塊或者同步方法時衅胀,程序中執(zhí)行了同步監(jiān)視器的wait()方法绢要,wait是object的方法,范圍是該object實例所在的線程

同步鎖

lock拗小,更加強大的線程同步機制重罪,通過顯式定義鎖對象來實現(xiàn)同步,也就是Lock對象哀九,線程在訪問共享資源之前剿配,需要先獲得鎖對象。線程安全控制中比較常用的是ReetrantLock可重入鎖阅束。一個線程可以對已經(jīng)加鎖的ReetrantLock再度加鎖呼胚。

class X{
        private final ReentrantLock lock = new ReentrantLock();
        
        //需要定義線程安全的方法
        public void foo() {
            lock.lock();//加鎖
            try {
                // 需要保證線程安全的代碼
            }
            finally {
                lock.unlock();//使用finally塊保證釋放鎖
            }
        }
    }

線程通信

Object類提供的wait(),notify(),notifyAll()三個方法

  • wait(): 當(dāng)前線程等待或者等待若干ms息裸,當(dāng)前線程自動釋放同步監(jiān)視器蝇更,線程進入等待狀態(tài)(阻塞)沪编,直到其他線程調(diào)用了該同步監(jiān)視器的notify()或者notifyAll方法。
  • notify():喚醒在同步監(jiān)視器上等待的單個線程年扩,若有多個線程等待蚁廓,則任意選擇其中一個。
  • notifyAll():喚醒在此同步監(jiān)視器上等待的所有線程厨幻。

Condition控制線程通信

使用Condition控制線程通信:使用Lock對象來保證同步問題時相嵌,我們可以使用Condition類來釋放Lock以及喚醒其他等待線程。

阻塞隊列(BlockingQueue)

當(dāng)生產(chǎn)者線程試圖向Blocking Queue中放入元素時况脆,如果隊列已滿饭宾,則該線程被阻塞,當(dāng)消費者線程試圖從BlockingQueue中取出元素時格了,如果隊列已空看铆,則該線程阻塞。

線程池

使用線程池執(zhí)行線程任務(wù)步驟:

  • 調(diào)用Executors類的靜態(tài)工廠方法創(chuàng)建一個ExecutorService對象盛末,該對象代表一個線程池弹惦。
  • 創(chuàng)建Runnable實現(xiàn)類或者Callable實現(xiàn)類的實例,作為線程的執(zhí)行任務(wù)满败。
  • 調(diào)用ExecutorService對象的submit方法來提交Runnable或者Callable實例肤频。
  • 當(dāng)沒有任務(wù)時,使用shutdown()方法來關(guān)閉線程池算墨。
public class Testjava{
  public static void main(String[] args)
  throws Exception{
      ExecutorService pool = Executors.newFixedThreadPool(6);
      Runnable target = ()->{
          for(int i=0;i<100;i++) {
          System.out.println(Thread.currentThread().getName()
                      + "的i值為:"+ i);
          }
      };      
      // 向線程池中提交兩個線程
      pool.submit(target);
      pool.submit(target);        
      pool.shutdown();
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宵荒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子净嘀,更是在濱河造成了極大的恐慌报咳,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挖藏,死亡現(xiàn)場離奇詭異暑刃,居然都是意外死亡,警方通過查閱死者的電腦和手機膜眠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門岩臣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宵膨,你說我怎么就攤上這事架谎。” “怎么了辟躏?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵谷扣,是天一觀的道長。 經(jīng)常有香客問我捎琐,道長会涎,這世上最難降的妖魔是什么裹匙? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮末秃,結(jié)果婚禮上概页,老公的妹妹穿的比我還像新娘。我一直安慰自己蛔溃,他們只是感情好绰沥,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布篱蝇。 她就那樣靜靜地躺著贺待,像睡著了一般。 火紅的嫁衣襯著肌膚如雪零截。 梳的紋絲不亂的頭發(fā)上麸塞,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音涧衙,去河邊找鬼哪工。 笑死,一個胖子當(dāng)著我的面吹牛弧哎,可吹牛的內(nèi)容都是我干的雁比。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼撤嫩,長吁一口氣:“原來是場噩夢啊……” “哼偎捎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起序攘,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤茴她,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后程奠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丈牢,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年瞄沙,在試婚紗的時候發(fā)現(xiàn)自己被綠了己沛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡距境,死狀恐怖申尼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肮疗,我是刑警寧澤晶姊,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站伪货,受9級特大地震影響们衙,放射性物質(zhì)發(fā)生泄漏钾怔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一蒙挑、第九天 我趴在偏房一處隱蔽的房頂上張望宗侦。 院中可真熱鬧,春花似錦忆蚀、人聲如沸矾利。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽男旗。三九已至,卻和暖如春欣鳖,著一層夾襖步出監(jiān)牢的瞬間察皇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工泽台, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留什荣,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓怀酷,卻偏偏與公主長得像稻爬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蜕依,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

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

  • ??一個任務(wù)通常就是一個程序桅锄,每個運行中的程序就是一個進程。當(dāng)一個程序運行時笔横,內(nèi)部可能包含了多個順序執(zhí)行流竞滓,每個順...
    OmaiMoon閱讀 1,663評論 0 12
  • 寫在之前 以下是《瘋狂Java講義》中的一些知識,如有錯誤吹缔,煩請指正商佑。 概述 ** 進程特征** 獨立性:進程是系...
    hainingwyx閱讀 371評論 0 0
  • 該文章轉(zhuǎn)自:http://blog.csdn.net/evankaka/article/details/44153...
    加來依藍閱讀 7,336評論 3 87
  • Java 多線程 線程和進程的區(qū)別 線程和進程的本質(zhì):由CPU進行調(diào)度的并發(fā)式執(zhí)行任務(wù),多個任務(wù)被快速輪換執(zhí)行厢塘,使...
    安安zoe閱讀 2,193評論 1 18
  • 己亥大年初一茶没,是在鞭炮與雞鳴聲中醒來的,但因為山村人少晚碾,聲音并不混亂抓半,反是熱鬧得恰到好處。洗漱過后格嘁,阿弟便匆匆出門...
    德音流韻閱讀 175評論 0 0