多線程1,線程基礎(chǔ)知識

多線程基礎(chǔ)知識

目錄介紹

  • 1.進程概述及多進程的意義[理解]
    • 1.1 線程和進程
    • 1.2 進程概述
    • 1.3 多進程的意義
  • 2.線程的概述和多線程的意義[理解]
    • 2.1 什么是線程
    • 2.2 多線程有什么意義
    • 2.3 并行和并發(fā)
  • 3.JVM運行原理以及JVM啟動的線程探討[理解]
    • 3.1 Java程序運行原理
    • 3.2 JVM的啟動是多線程的嗎
  • 4.多線程程序?qū)崿F(xiàn)的方式[掌握]
    • 4.1 多線程程序?qū)崿F(xiàn)的方式【重點】
    • 4.1.1 第一種方式:是類繼承Thread
    • 4.1.2 第二種方式:是實現(xiàn)接口Runnable
    • 4.2 多線程兩種方式的區(qū)別
    • 4.3 幾個小問題探索
    • 4.4 匿名內(nèi)部類的方式實現(xiàn)多線程程序
  • 5.線程調(diào)度
    • 5.1 線程的調(diào)度問題
    • 5.2 線程有兩種調(diào)度模型
  • 6.線程控制
    • 6.1 線程控制之休眠線程
    • 6.2 線程控制之加入線程
    • 6.3 線程控制之禮讓線程
    • 6.4 線程控制之守護線程
    • 6.5 線程控制之中斷線程
  • 7.案例分析
    • 7.1 繼承Thread類的方式賣電影票案例
    • 7.2 實現(xiàn)Runnable接口的方式賣電影票
    • 7.3 買電影票出現(xiàn)了同票和負數(shù)票的原因分析
    • 7.4 線程安全問題的產(chǎn)生原因分析
    • 7.5 同步代碼塊的方式解決線程安全問題

好消息

  • 博客筆記大匯總【16年3月到至今】吊圾,包括Java基礎(chǔ)及深入知識點,Android技術(shù)博客,Python學(xué)習(xí)筆記等等喘鸟,還包括平時開發(fā)中遇到的bug匯總,當然也在工作之余收集了大量的面試題驻右,長期更新維護并且修正什黑,持續(xù)完善……開源的文件是markdown格式的!同時也開源了生活博客堪夭,從12年起愕把,積累共計47篇[近20萬字]拣凹,轉(zhuǎn)載請注明出處,謝謝恨豁!
  • 鏈接地址:https://github.com/yangchong211/YCBlogs
  • 如果覺得好嚣镜,可以star一下,謝謝橘蜜!當然也歡迎提出建議菊匿,萬事起于忽微,量變引起質(zhì)變计福!

0.前沿介紹

1.進程概述及多進程的意義[理解]

1.1 線程和進程

  • 要想說線程力麸,首先必須得聊聊進程可款,因為線程是依賴于進程存在的。

1.2 進程概述

  • 什么是進程呢?通過任務(wù)管理器我們就可以看到進程的存在克蚂。
  • 概念:進程就是正在運行的程序闺鲸,是系統(tǒng)進行資源分配和調(diào)用的獨立單位。每一個進程都有它自己的內(nèi)存空間和系統(tǒng)資源埃叭。

1.3 多進程的意義

  • 單進程計算機只能做一件事情摸恍。而我們現(xiàn)在的計算機都可以一邊玩游戲(游戲進程),一邊聽音樂(音樂進程),所以我們常見的操作系統(tǒng)都是多進程操作系統(tǒng)赤屋。比如:Windows立镶,Mac和Linux等,能在同一個時間段內(nèi)執(zhí)行多個任務(wù)类早。
  • 對于單核計算機來講媚媒,游戲進程和音樂進程是同時運行的嗎?不是。
  • 因為CPU在某個時間點上只能做一件事情涩僻,計算機是在游戲進程和音樂進程間做著頻繁切換缭召,且切換速度很快,
  • 所以逆日,我們感覺游戲和音樂在同時進行嵌巷,其實并不是同時執(zhí)行的。多進程的作用不是提高執(zhí)行速度室抽,而是提高CPU的使用率搪哪。

2.線程的概述和多線程的意義[理解]

2.1 什么是線程

  • 在一個進程內(nèi)部又可以執(zhí)行多個任務(wù),而這每一個任務(wù)我們就可以看成是一個線程坪圾。是程序使用CPU的基本單位晓折。

2.2 多線程有什么意義

  • 多線程的作用不是提高執(zhí)行速度惑朦,而是為了提高應(yīng)用程序的使用率。
  • 那么怎么理解這個問題呢?我們程序在運行的使用,都是在搶CPU的時間片(執(zhí)行權(quán)),如果是多線程的程序,那么在搶到CPU的執(zhí)行權(quán)的概率應(yīng)該比較單線程程序搶到的概率要大.那么也就是說,CPU在多線程程序中執(zhí)行的時間要比單線程多,所以就提高了程序的使用率.但是即使是多線程程序,那么他們中的哪個線程能搶占到CPU的資源呢,這個是不確定的,所以多線程具有隨機性.

2.3 并行和并發(fā)

  • 前者是邏輯上同時發(fā)生漓概,指在某一個時間內(nèi)同時運行多個程序行嗤。
  • 后者是物理上同時發(fā)生,指在某一個時間點同時運行多個程序垛耳。

3.JVM運行原理以及JVM啟動的線程探討[理解]

3.1 Java程序運行原理

  • Java命令會啟動java虛擬機,啟動JVM飘千,等于啟動了一個應(yīng)用程序堂鲜,也就是啟動了一個進程。
  • 該進程會自動啟動一個 “主線程” 护奈,然后主線程去調(diào)用某個類的 main 方法缔莲。所以 main方法運行在主線程中。

3.2 JVM的啟動是多線程的嗎

  • JVM啟動至少啟動了垃圾回收線程和主線程霉旗,所以是多線程的痴奏。

4.多線程程序?qū)崿F(xiàn)的方式[掌握]

4.1 多線程程序?qū)崿F(xiàn)的方式

  • 4.1.1 第一種方式:是類繼承Thread
第一種方式的步驟:
1: 定義一個類,讓該類去繼承Thread類
2: 重寫run方法
3: 創(chuàng)建該類的對象
4: 啟動線程

public class ThreadDemo {
    public static void main(String[] args) {
        // 創(chuàng)建對象
        MyThread t1 = new MyThread() ;
        MyThread t2 = new MyThread() ;
        // 啟動線程: 需要使用start方法啟動線程, 如果我們在這里調(diào)用的是run方法,那么我們只是把該方法作為普通方法進行執(zhí)行
//      t1.run() ;
//      t1.run() ;
        t1.start() ;        // 告訴jvm開啟一個線程調(diào)用run方法
        // t1.start() ;     // 一個線程只能被啟動一次
        t2.start() ;
        
    }
}

public class MyThread extends Thread {
    @Override
    public void run() {
        for(int x = 0 ; x < 1000 ; x++) {
            System.out.println(x);
        }
    }
}
  • 4.1.2 第二種方式:是實現(xiàn)接口Runnable
實現(xiàn)多線程的第二中方式步驟:
1: 定義一個類,讓該類去實現(xiàn)Runnable接口
2: 重寫run方法
3: 創(chuàng)建定義的類的對象
4: 創(chuàng)建Thread的對象吧第三步創(chuàng)建的對象作為參數(shù)傳遞進來
5: 啟動線程

public static void main(String[] args) {
    // 創(chuàng)建定義的類的對象
    MyThread mt = new MyThread() ;
    // 創(chuàng)建Thread的對象吧第三步創(chuàng)建的對象作為參數(shù)傳遞進來
    Thread t1 = new Thread(mt , "張三") ;
    Thread t2 = new Thread(mt , "李四") ;
    // 啟動線程
    t1.start() ;
    t2.start() ;
}

public class MyThread implements Runnable {
    @Override
    public void run() {
        for(int x = 0 ; x < 1000 ; x++) {
            System.out.println(Thread.currentThread().getName() + "---" + x);
        }
        
    }
}

4.2 多線程兩種方式的區(qū)別

  • run()方法只是調(diào)用了Thread實例的run()方法而已,它仍然運行在主線程上厌秒,而start()方法會開辟一個新的線程读拆,在新的線程上調(diào)用run()方法,此時它運行在新的線程上鸵闪。

4.3 幾個小問題探索

  • 4.3.1 為什么要重寫run方法
  • 可以在定義的類中,定義多個方法,而方法中的代碼并不是所有的都需要線程來進行執(zhí)行; 如果我們想讓某一個段代碼被線程,那么我們只需要將那一段代碼放在run方法中檐晕。那么也就是說run方法中封裝的都是要被線程執(zhí)行的代碼 ;
  • run方法中的代碼的特點: 封裝的都是一些比較耗時的代碼
  • 4.3.2 線程能不能多次啟動
  • 一個線程只能被啟動一次
  • 4.3.2 run()和start()方法的區(qū)別
  • 啟動線程: 需要使用start方法啟動線程, 如果我們在這里調(diào)用的是run方法蚌讼,那么我們只是把該方法作為普通方法進行執(zhí)行辟灰。

4.4 匿名內(nèi)部類的方式實現(xiàn)多線程程序

  • new Thread(){代碼…}.start();
  • new Thread(new Runnable(){代碼…}).start();

5.線程調(diào)度

5.1 線程的調(diào)度問題

  • 應(yīng)用程序在執(zhí)行的時候都需要依賴于線程去搶占CPU的時間片 , 誰搶占到了CPU的時間片,那么CPU就會執(zhí)行誰
  • 線程的執(zhí)行:假如我們的計算機只有一個 CPU,那么 CPU在某一個時刻只能執(zhí)行一條指令篡石,線程只有得到CPU時間片芥喇,也就是使用權(quán),才可以執(zhí)行指令凰萨。

5.2 線程有兩種調(diào)度模型

  • 5.2.1 分時調(diào)度模型
  • 所有線程輪流使用CPU的使用權(quán)继控,平均分配每個線程占用 CPU 的時間片
  • 5.2.2 搶占式調(diào)度模型
  • 優(yōu)先讓優(yōu)先級高的線程使用 CPU,如果線程的優(yōu)先級相同沟蔑,那么會隨機選擇一個湿诊,優(yōu)先級高的線程獲取的 CPU 時間片相對多一些。Java使用的是搶占式調(diào)度模型瘦材。

6.線程控制

6.1 線程控制之休眠線程

  • public static void sleep(long time) ;
  • time表達的意思是休眠的時間 , 單位是毫秒

6.2 線程控制之加入線程

  • public final void join()
  • 等待該線程執(zhí)行完畢了以后,其他線程才能再次執(zhí)行
  • 注意事項: 在線程啟動之后,在調(diào)用方法

6.3 線程控制之禮讓線程

  • public static void yield():
  • 暫停當前正在執(zhí)行的線程對象厅须,并執(zhí)行其他線程。
  • 線程禮讓的原理是: 暫定當前的線程,然CPU去執(zhí)行其他的線程, 這個暫定的時間是相當短暫的; 當我某一個線程暫定完畢以后,其他的線程還沒有搶占到cpu的執(zhí)行權(quán) ; 那么這個是時候當前的線程會和其他的線程再次搶占cpu的執(zhí)行權(quán);

6.4 線程控制之守護線程

  • public final void setDaemon(boolean on)
  • 將該線程標記為守護線程或用戶線程食棕。當正在運行的線程都是守護線程時朗和,Java 虛擬機退出错沽。 該方法必須在啟動線程前調(diào)用。
  • jvm會線程程序中存在的線程類型,如果線程全部是守護線程,那么jvm就停止眶拉。

6.5 線程控制之中斷線程

  • public final void stop():
  • 停止線程的運行
  • public void interrupt():
  • 中斷線程(這個翻譯不太好),查看API可得當線程調(diào)用wait(),sleep(long time)方法的時候處于阻塞狀態(tài),可以通過這個方法清除阻塞

7.案例分析

7.1 繼承Thread類的方式賣電影票案例

public class ThreadDemo {
    public static void main(String[] args) {
        /**
         * 需求:某電影院目前正在上映賀歲大片千埃,共有100張票,而它有3個售票窗口售票忆植,請設(shè)計一個程序模擬該電影院售票放可。
         */
        // 創(chuàng)建3個線程對象
        SellTicktes t1 = new SellTicktes() ;
        SellTicktes t2 = new SellTicktes() ;
        SellTicktes t3 = new SellTicktes() ;
        // 設(shè)置名稱
        t1.setName("窗口1") ;
        t2.setName("窗口2") ;
        t3.setName("窗口3") ;
        // 啟動線程
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}

public class SellTicktes extends Thread {
    private static int num = 100 ;
    @Override
    public void run() {
        /**
         * 定義總票數(shù)
         * 
         * 如果我們把票數(shù)定義成了局部變量,那么表示的意思是每一個窗口出售了各自的100張票; 而我們的需求是: 總共有100張票
         * 而這100張票要被3個窗口出售; 因此我們就不能把票數(shù)定義成局部變量,只能定義成成員變量
         */     
        // 模擬售票
        while(true) {
            if( num > 0 ) {
                System.out.println(Thread.currentThread().getName() + "正在出售" + (num--) + "張票");
            }
        }
    }
}

7.2 實現(xiàn)Runnable接口的方式賣電影票

public class SellTicektesDemo {
    public static void main(String[] args) {
        // 創(chuàng)建SellTicektes對象
        SellTicektes st = new SellTicektes() ;
        // 創(chuàng)建Thread對象
        Thread t1 = new Thread(st , "窗口1") ;
        Thread t2 = new Thread(st , "窗口2") ;
        Thread t3 = new Thread(st , "窗口3") ;
        // 啟動線程
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}

public class SellTicektes implements Runnable {
    private static int num = 100 ;
    @Override
    public void run() {
        while(true) {
            if(num > 0) {
                System.out.println(Thread.currentThread().getName() + "正在出售第" + (num--) + "張票");
            }
        }
    }
}

7.3 買電影票出現(xiàn)了同票和負數(shù)票的原因分析

  • 講解過電影院售票程序,從表面上看不出什么問題朝刊,但是在真實生活中耀里,售票時網(wǎng)絡(luò)是不能實時傳輸?shù)模偸谴嬖谘舆t的情況拾氓,所以冯挎,在出售一張票以后,需要一點時間的延遲咙鞍。改實現(xiàn)接口方式的賣票程序,每次賣票延遲100毫秒
public class ThreadDemo {
    public static void main(String[] args) {
        // 創(chuàng)建3個線程對象
        SellTicktes t1 = new SellTicktes() ;
        SellTicktes t2 = new SellTicktes() ;
        SellTicktes t3 = new SellTicktes() ;
        // 設(shè)置名稱
        t1.setName("窗口1") ;
        t2.setName("窗口2") ;
        t3.setName("窗口3") ;
        // 啟動線程
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}

public class SellTicktes extends Thread {
    private static int num = 100 ;
    @Override
    public void run() {
        // 模擬售票
        while(true) {
            if( num > 0 ) {
                try {
                    Thread.sleep(100) ;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在出售" + (num--) + "張票");
            }
        }
    }
}

7.4 線程安全問題的產(chǎn)生原因分析

  • 7.4.1 首先想為什么出現(xiàn)問題?
  • 是否是多線程環(huán)境房官,是否有共享數(shù)據(jù),是否有多條語句操作共享數(shù)據(jù)
  • 7.4.2 如何解決多線程安全問題呢?
  • 基本思想:讓程序沒有安全問題的環(huán)境续滋。怎么實現(xiàn)呢?把多個語句操作共享數(shù)據(jù)的代碼給鎖起來翰守,讓任意時刻只能有一個線程執(zhí)行即可。

7.5 同步代碼塊的方式解決線程安全問題

  • 7.5.1 同步代碼塊的格式
  • 同步可以解決安全問題的根本原因就在那個對象上疲酌。該對象如同鎖的功能
synchronized(對象){
            需要同步的代碼;
        }
  • 7.5.2 同步代碼塊優(yōu)勢和劣勢
  • 同步的好處:同步的出現(xiàn)解決了多線程的安全問題潦俺。
  • 同步的弊端:當線程相當多時,因為每個線程都會去判斷同步上的鎖徐勃,這是很耗費資源的事示,無形中會降低程序的運行效率。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末僻肖,一起剝皮案震驚了整個濱河市肖爵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌臀脏,老刑警劉巖劝堪,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異揉稚,居然都是意外死亡秒啦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門搀玖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來余境,“玉大人,你說我怎么就攤上這事》祭矗” “怎么了含末?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長即舌。 經(jīng)常有香客問我佣盒,道長,這世上最難降的妖魔是什么顽聂? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任肥惭,我火速辦了婚禮,結(jié)果婚禮上紊搪,老公的妹妹穿的比我還像新娘务豺。我一直安慰自己,他們只是感情好嗦明,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蚪燕,像睡著了一般娶牌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上馆纳,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天诗良,我揣著相機與錄音,去河邊找鬼鲁驶。 笑死鉴裹,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的钥弯。 我是一名探鬼主播径荔,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼脆霎!你這毒婦竟也來了总处?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤睛蛛,失蹤者是張志新(化名)和其女友劉穎鹦马,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忆肾,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡荸频,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了客冈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旭从。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出遇绞,到底是詐尸還是另有隱情键袱,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布摹闽,位于F島的核電站蹄咖,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏付鹿。R本人自食惡果不足惜澜汤,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望舵匾。 院中可真熱鬧俊抵,春花似錦、人聲如沸坐梯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吵血。三九已至谎替,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蹋辅,已是汗流浹背钱贯。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留侦另,地道東北人秩命。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像褒傅,于是被迫代替她去往敵國和親弃锐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

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

  • 又來到了一個老生常談的問題殿托,應(yīng)用層軟件開發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢拿愧? 今天就這個問題開始,來談?wù)劜?..
    tangsl閱讀 4,104評論 0 23
  • Java8張圖 11碌尔、字符串不變性 12浇辜、equals()方法、hashCode()方法的區(qū)別 13唾戚、...
    Miley_MOJIE閱讀 3,697評論 0 11
  • 寫在前面的話: 這篇博客是我從這里“轉(zhuǎn)載”的柳洋,為什么轉(zhuǎn)載兩個字加“”呢?因為這絕不是簡單的復(fù)制粘貼叹坦,我花了五六個小...
    SmartSean閱讀 4,717評論 12 45
  • 很多心靈雞湯都慫恿我們說“要勇敢踏出第一步”熊镣,一旦涉足,來自不同的煩惱便紛至沓來。我們需要做好應(yīng)付準備
    辛小毛閱讀 94評論 0 0
  • 2018年4月7日 星期六 晴 假期最后一天绪囱,今天上班中测蹲。早晨李云哲說還有一篇作文沒寫,要跟我去公司寫...
    云哲云燦媽媽閱讀 25評論 0 0