Java多線程與并發(fā)

進(jìn)程和線程的區(qū)別

進(jìn)程和線程的由來(lái)

image.png

進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位

  • 所有與進(jìn)程相關(guān)的資源,都被記錄在PCB中

  • 進(jìn)程是搶占處理機(jī)的調(diào)度單位;線程屬于某個(gè)進(jìn)程,共享其資源

  • 線程只有堆棧寄存器、程序計(jì)數(shù)器和TCB(線程控制表)組成

總結(jié)

  • 線程不能看做獨(dú)立應(yīng)用,而進(jìn)程可看做獨(dú)立應(yīng)用

  • 進(jìn)程有獨(dú)立的地址空間,互相不影響,線程只是進(jìn)程的不同執(zhí)行路徑

  • 線程沒(méi)有獨(dú)立的地址空間,多進(jìn)程的程序比多線程的程序健壯

  • 進(jìn)程的切換比線程的切換開(kāi)銷大

Java進(jìn)程和線程的關(guān)系

  • Java對(duì)操作系統(tǒng)提供的功能進(jìn)行封裝,包括進(jìn)程和線程

  • 運(yùn)行一個(gè)程序會(huì)產(chǎn)生一個(gè)進(jìn)程,進(jìn)程包含至少一個(gè)線程

  • 每個(gè)進(jìn)程對(duì)應(yīng)一個(gè)JVM實(shí)例,多個(gè)線程共享JVM里的堆

  • Java采用單線程編程模型,程序會(huì)自動(dòng)創(chuàng)建主線程

  • 主線程可以創(chuàng)建子線程,原則上要后于子線程完成執(zhí)行

進(jìn)程間通信

  • 管道:速度慢,容量有限,只有父子進(jìn)程能通訊

  • FIFO:任何進(jìn)程間都能通訊,但速度慢

  • 消息隊(duì)列:容量受到系統(tǒng)限制,且要注意第一次讀的時(shí)候,要考慮上一次沒(méi)有讀完數(shù)據(jù)的問(wèn)題

  • 信號(hào)量:不能傳遞復(fù)雜消息,只能用來(lái)同步

  • 共享內(nèi)存區(qū):能夠很容易控制容量,速度快,但要保持同步,比如一個(gè)進(jìn)程在寫的時(shí)候,另一個(gè)進(jìn)程要注意讀寫的問(wèn)題,相當(dāng)于線程中的線程安全,當(dāng)然,共享內(nèi)存區(qū)同樣可以用作線程間通訊,不過(guò)沒(méi)這個(gè)必要,線程間本來(lái)就已經(jīng)共享了同一進(jìn)程內(nèi)的一塊內(nèi)存

Thread中的run和start的區(qū)別

  • 調(diào)用start()方法會(huì)創(chuàng)建一個(gè)新的子線程并啟動(dòng)

  • run()方法只是Thread的一個(gè)普通方法的調(diào)用

Thread和Runnable的關(guān)系

  • Thread是實(shí)現(xiàn)了Runnable接口的類,使得run支持多線程

  • 因類的單一繼承原則,推薦多使用Runnable接口

public class MyRunnable implements Runnable {

    private String name;

    public MyRunnable(String name){

        this.name = name;

    }

    @Override

    public void run() {

        for (int i = 0; i < 10; i++) {

            System.out.println("Thread start:" + this.name + ",i=" + i);

        }

    }

    public static void main(String[] args) {

        MyRunnable mr1 = new MyRunnable("Runnable1");

        MyRunnable mr2 = new MyRunnable("Runnable2");

        MyRunnable mr3 = new MyRunnable("Runnable3");

        Thread t1 = new Thread(mr1);

        Thread t2 = new Thread(mr2);

        Thread t3 = new Thread(mr3);

        t1.start();

        t2.start();

        t3.start();

    }

}

如何給run()方法傳參

  • 構(gòu)造函數(shù)傳參

  • 成員變量傳參

  • 回調(diào)函數(shù)傳參

如何實(shí)現(xiàn)處理線程的返回值

  • 主線程等待法

  • 使用Thread類的join()阻塞當(dāng)前線程以等待子線程處理完畢

  • 通過(guò)Callable接口實(shí)現(xiàn):通過(guò)FutureTask或者線程池獲取

import java.util.concurrent.*;

/**

* @author lijiayin

*/

public class MyCallable implements Callable<String> {

    @Override

    public String call() throws Exception {

        String value = "test";

        System.out.println("Ready to work");

        Thread.sleep(5000);

        System.out.println("Work finish");

        return value;

    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        FutureTask<MyCallable> futureTask = new FutureTask(new MyCallable());

        new Thread(futureTask).start();

        if(!futureTask.isDone()){

            System.out.println("Work not finish");

        }

        System.out.println("return value : " + futureTask.get());

        ExecutorService executorService = Executors.newCachedThreadPool();

        Future<String> future = executorService.submit(new MyCallable());

        if(!future.isDone()){

            System.out.println("Work not finish");

        }

        try{

            System.out.println("return value : " + future.get());

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            executorService.shutdown();

        }

    }

}

線程的狀態(tài)

  • 新建(New):創(chuàng)建后尚未啟動(dòng)的線程狀態(tài)

  • 運(yùn)行(Runnable):包含Running和Ready

    • 無(wú)限期等待(Waiting):不會(huì)被分配CPU執(zhí)行時(shí)間,需要顯式被喚醒

    • 沒(méi)有設(shè)置Timeout參數(shù)的Object.wait()方法

    • 沒(méi)有設(shè)置Timeout參數(shù)的Thread.join()方法

    • LockSupport.park()方法

  • 限期等待(Timed Waiting):在一定時(shí)間后會(huì)由系統(tǒng)自動(dòng)喚醒

    • Thread.sleep()方法

    • 設(shè)置了Timeout參數(shù)的Object.wait()方法

    • 設(shè)置了Timeout參數(shù)的Thread.join()方法

    • LockSupport.parkNanos()方法

    • LockSupport.parkUntil()方法

  • 阻塞(Blocked):等待獲取排它鎖

  • 結(jié)束(Terminated):已終止線程的狀態(tài),線程已經(jīng)結(jié)束執(zhí)行

sleep和wait的區(qū)別

基本的差別

  • sleep是Thread類的方法,wait是Object類中定義的方法

  • sleep()方法可以在任何地方使用

  • wait()方法只能在synchronized方法或者synchronized塊中使用

最主要的本質(zhì)區(qū)別

  • Thread.sleep只會(huì)讓出CPU,不會(huì)導(dǎo)致鎖行為的改變

  • Object.wait不僅讓出CPU,還會(huì)釋放已經(jīng)占有的同步資源鎖

notify和notifyAll的區(qū)別

兩個(gè)概念

  • 鎖池EntryList:假設(shè)線程A已經(jīng)擁有了某個(gè)對(duì)象(不是類)的鎖,而其它線程B、C想要調(diào)用這個(gè)對(duì)象的synchronized方法(或者塊),由于B、C線程在進(jìn)入對(duì)象的synchronized方法(或者塊)之前必須獲得該對(duì)象鎖的擁有權(quán),而恰巧該對(duì)象的鎖目前正被線程A所占用,此時(shí)B、C線程就會(huì)被阻塞,進(jìn)入一個(gè)地方去等待鎖的釋放,這個(gè)地方便是該對(duì)象的鎖池。

  • 等待池WaitSet:假設(shè)線程A調(diào)用了某個(gè)對(duì)象的wait()方法,線程A就會(huì)釋放該對(duì)象的鎖,同時(shí)線程A就進(jìn)入到了該對(duì)象的等待池中,進(jìn)入到等待池中的線程不會(huì)去競(jìng)爭(zhēng)該對(duì)象的鎖。

結(jié)論

  • notifyAll會(huì)讓所有處于等待池的線程全部進(jìn)入鎖池去競(jìng)爭(zhēng)獲取鎖的機(jī)會(huì)。

  • notify只會(huì)隨機(jī)選取一個(gè)處于等待池中的線程進(jìn)入鎖池去競(jìng)爭(zhēng)獲取鎖的機(jī)會(huì)。

yield

概念

當(dāng)調(diào)用Thread.yield()函數(shù)時(shí),會(huì)給線程調(diào)度器一個(gè)當(dāng)前線程愿意讓出CPU使用的暗示,但是線程調(diào)度器可能會(huì)忽略這個(gè)暗示。

對(duì)鎖行為沒(méi)有影響。

interrupt函數(shù)

通知線程應(yīng)該中斷了

  • 如果線程處于被阻塞狀態(tài),那么線程將立即退出被阻塞狀態(tài),并拋出一個(gè)InterruptedException異常

  • 如果線程處于正常活動(dòng)狀態(tài),那么會(huì)將該線程的中斷標(biāo)志設(shè)置為true。被設(shè)置中斷標(biāo)志的線程將繼續(xù)正常運(yùn)行,不受影響。

需要被調(diào)用的線程配合中斷

  • 在正常運(yùn)行任務(wù)時(shí),經(jīng)常檢查本線程的中斷標(biāo)志位,如果被設(shè)置了中斷就自行停止線程。

  • 如果線程處于正?;顒?dòng)狀態(tài),那么會(huì)將該線程的中斷標(biāo)志設(shè)置為true。被設(shè)置中斷標(biāo)志的線程將繼續(xù)正常運(yùn)行,不受影響。

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. 計(jì)算機(jī)系統(tǒng) 使用高速緩存來(lái)作為內(nèi)存與處理器之間的緩沖,將運(yùn)算需要用到的數(shù)據(jù)復(fù)制到緩存中,讓計(jì)算能快速進(jìn)行;當(dāng)...
    AI喬治閱讀 586評(píng)論 0 12
  • 一 進(jìn)程與線程的區(qū)別 1. 進(jìn)程和線程的由來(lái)串行 : 初期的計(jì)算機(jī)只能串行執(zhí)行任務(wù),并且需要長(zhǎng)時(shí)間等待用戶輸入;批...
    十丈_紅塵閱讀 173評(píng)論 0 1
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 3,115評(píng)論 1 18
  • 林炳文Evankaka原創(chuàng)作品。轉(zhuǎn)載自http://blog.csdn.net/evankaka 本文主要講了ja...
    ccq_inori閱讀 741評(píng)論 0 4
  • 當(dāng)一個(gè)javascript文件很大的時(shí)候,會(huì)出現(xiàn)一些問(wèn)題:1.里面定義了大量的變量,你不得不把變量的名字寫的越來(lái)越...
    我是漸漸呀閱讀 448評(píng)論 0 0

友情鏈接更多精彩內(nèi)容