多線程(第一篇)

線程與進程

進程:正在運行的程序。
線程:一個進程的執(zhí)行單元阔籽。一條執(zhí)行流程流妻。
多線程:一個進程中有多條執(zhí)行路徑。

  • 進程(Process)
    狹義定義:進程是正在運行的程序的實例
    廣義定義:進程是一個具有一定獨立功能的程序關(guān)于某個數(shù)據(jù)集合的一次運行活動笆制。它是操作系統(tǒng)動態(tài)執(zhí)行的基本單元绅这,在傳統(tǒng)的操作系統(tǒng)中,進程既是基本的分配單元在辆,也是基本的執(zhí)行單元证薇。
    多進程可以提高CPU的使用率
  • 線程(Thread)
    線程是程序中一個單一的順序控制流程。進程內(nèi)的執(zhí)行單元匆篓,是CPU的基本單位浑度。
  • 多線程
    在單個程序中同時運行多個線程完成不同的工作,稱為多線程鸦概。
    作用:
    為了提高效率才使用箩张。
    什么時候使用?
    只有當要操作的代碼的內(nèi)容比較多(耗時),循環(huán)次數(shù)較多這樣的情況才使用。

多線程的生命周期

image.png

多線程的實現(xiàn)方式

Java是不能直接調(diào)用系統(tǒng)功能的窗市,所以先慷,我們沒辦法直接實現(xiàn)多線程程序。
所以Java可以去調(diào)用C/C++寫好的程序來實現(xiàn)程序的多線程咨察。由C/C++去調(diào)用系統(tǒng)功
能創(chuàng)建進程论熙,然后Java去調(diào)用,然后提供一些類供我們使用摄狱,我們就可以實現(xiàn)多線程了
Java提供的是Thread類赴肚,通過API知道其有2種方法實現(xiàn)多線程
(創(chuàng)建新執(zhí)行線程有兩種方法素跺。一種方法是將類聲明為 Thread 的子類。
該子類應(yīng)重寫 Thread 類的 run 方法誉券。接下來可以分配并啟動該子類的實例)

Thread類的方法:

void setName(String name)
-- 設(shè)置線程的名稱
String getName()
-- 獲取線程的名稱
static Thread currentThread()
-- 獲取當前正在運行的線程對象

方式1:繼承Thread類的方式

步驟 :
A:自定義類繼承Thread類
B:自定義類中重寫run()方法
為什么是run()方法呢?
C:創(chuàng)建對象
D:啟動線程
注意:

  1. 為什么是run()方法呢刊愚?
    不是類中所有的代碼都需要被線程執(zhí)行的踊跟。
    而這個時候,為了區(qū)分那些代碼能被線程執(zhí)行鸥诽,java提供了Thread類中的run()
    用來包含那些被線程執(zhí)行的代碼商玫。
  2. run()和start()的區(qū)別?
  • start():首先啟動了線程牡借,然后由jvm去調(diào)用該線程的run()方法
  • run():僅僅是封裝線程的方法拳昌,直接調(diào)用是普通的方法
package com.lianwei.Thread.ExtendsThread;


 package com.lianwei.Thread.ExtendsThread;
import com.sun.org.apache.xml.internal.resolver.helpers.PublicId;
 
public class MyThread extends Thread{
    //構(gòu)造方法起名字
    public MyThread(String name) {
        super(name);
    }

    public MyThread() {

    }

    public void run(){
        for (int x=1;x<=10;x++){
            System.out.println(getName()+"=>"+x);
        }
    }
}
public class MyThreadDemo {
    public static void main(String[] args){
        //獲取main方法所在的線程對象的名稱,該腫么辦钠龙?
        //public static Thread currentThread():返回當前在線的線程對象
        System.out.println(Thread.currentThread().getName());

            //        調(diào)用方法設(shè)置名稱
//        //創(chuàng)建線程對象
//        MyThread mt1 = new MyThread();
//        MyThread mt2 = new MyThread();
//        //設(shè)置線程名稱
//        mt1.setName("康娜");
//        mt2.setName("jyh");
//        //啟動線程
//        mt1.start();
//        mt2.start();

        //        帶參構(gòu)造方法給線程起名字
        MyThread my1 = new MyThread("康娜");
        MyThread my2 = new MyThread("jyh");
        my1.start();
        my2.start();
    }
}

方式2:實現(xiàn)Runnable接口的方式

優(yōu)點:
1)可以避免單繼承的局限性炬藤。
2)只創(chuàng)建了一個資源對象。更好的實現(xiàn)了數(shù)據(jù)與操作的分離碴里。
(一般我們選擇第二種方式沈矿。)

        package com.lianwei.Thread.ImpRunable;
import java.lang.Runnable;
public class ImplementsRunnable implements Runnable{
    public void run(){
        for (int x=0;x<10;x++){
//由于實現(xiàn)接口的方式不能直接使用Thread類的方法了,但可以間接使用
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
    }
}
package com.lianwei.Thread.ImpRunable;
//步驟:
//    A:創(chuàng)建一個類實現(xiàn)Runnable接口
//    B:重寫run()方法
//    C:創(chuàng)建類的對象
//    D:把該對象作為Thread類的構(gòu)造參數(shù)傳遞咬腋。創(chuàng)建Thread類的對象羹膳,并執(zhí)行。
public class Runnable {
    public static void main(String[] args){
        ImplementsRunnable im = new ImplementsRunnable();
//    D:把該對象作為Thread類的構(gòu)造參數(shù)傳遞根竿。創(chuàng)建Thread類的對象陵像,并執(zhí)行。
//          Thread(Runnable target)
//        Thread t1 = new Thread(im);
//        Thread t2 = new Thread(im);
//        t1.setName("康娜");
//        t2.setName("jyh");

//         Thread(Runnable target,String name)
        Thread t1 =new Thread(im,"康娜");
        Thread t2 =new Thread(im,"jyh");
        t1.start();
        t2.start();
    }
}

線程優(yōu)先級

  • 線程優(yōu)先級級別
    線程默認優(yōu)先級是5寇壳。范圍是1-10
 Thread.MAX_PRIORITY         //10 
 Thread.MIN_PRIORITY         //1 
 Thread.NORM_PRIORITY           //5 
  • 方法
    int getPriority()
    -- 獲取線程優(yōu)先級醒颖。
    void setPriority(int pri)
    -- 設(shè)置線程的優(yōu)先級。
  • 注意
    較高的優(yōu)先級會給線程更多的執(zhí)行機會九巡,但不保證優(yōu)先級高的一定先執(zhí)行图贸。
    優(yōu)先級可以在一定的程度上(即更大的概率)讓線程獲較多的執(zhí)行機會

線程調(diào)度(了解)

  • 分時調(diào)度模型:所有線程輪流使用CPU的使用權(quán),平均分配每個線程的時間
  • 搶占式調(diào)度模型:隨機分配使用權(quán)冕广,優(yōu)先級高的使用幾率大一點疏日。

線程控制

線程休眠

package com.lianwei.Thread.ControlThread;
import java.util.Date;
public class ThreadSleep extends Thread{
    public void run(){
        for (int x=1;x<=10;x++){
            System.out.println(getName()+":"+x+"日期:"+new Date());
            //睡眠1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.lianwei.Thread.ControlThread;
import com.lianwei.Thread.ExtendsThread.MyThread;
public class ThreadSleepDemo {
    public static void main(String[] args) {
        //創(chuàng)建線程對象
        ThreadSleep mt1 = new ThreadSleep();
        ThreadSleep mt2 = new ThreadSleep();
        //設(shè)置線程名稱
        mt1.setName("康娜");
        mt2.setName("jyh");
        //啟動線程
        mt1.start();
        mt2.start();
    }
}

線程加入

package com.lianwei.Thread.ControlThread;
import java.util.Date;
public class ThreadJoin extends Thread{
    public void run(){
        for (int x=1;x<=10;x++){
            System.out.println(getName()+":"+x+"日期:"+new Date());
        }
    }
}
package com.lianwei.Thread.ControlThread;
public class ThreadJoinDemo {
    public static void main(String[] args) {
        //創(chuàng)建線程對象
        ThreadJoin tj1 = new ThreadJoin();
        ThreadJoin tj2 = new ThreadJoin();
        ThreadJoin tj3 = new ThreadJoin();

        tj1.setName("動物");
        tj2.setName("貓");
        tj3.setName("狗");
        tj1.start();
        try {
            tj1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        tj2.start();
        tj3.start();
    }
}

線程禮讓

package com.lianwei.Thread.ControlThread;
import java.util.Date;
public class ThreadYield extends ThreadJoin{
    public void run(){
        for (int x=1;x<=10;x++){
            System.out.println(getName()+":"+x+"日期:"+new Date());
            Thread.yield();
        }
    }
}
package com.lianwei.Thread.ControlThread;
//public static void yield():暫停當前的線程,并執(zhí)行其他的線程
//它可以讓線程跟和諧撒汉,但還是不能保證一人一次
public class ThreadYieldDemo {
    public static void main(String[] args){
        ThreadYield ty1 = new ThreadYield();
        ThreadYield ty2 = new ThreadYield();
        ty1.setName("康娜");
        ty2.setName("jyh");
    }
}

后臺線程

package com.lianwei.Thread.ControlThread;
import java.util.Date;
public class ThreadDaemon extends ThreadJoin{
    public void run(){
        for (int x=1;x<=100;x++){
            System.out.println(getName()+":"+x);
        }
    }
}
package com.lianwei.Thread.ControlThread;
//public final void setDaemon(boolean on):將該線程標記為守護線程或用戶線程
//當正在運行的線程都是守護線程時沟优,java虛擬機退出,該方法必須在啟動前調(diào)用
public class ThreadDaemonDemo {
    public static void main(String[] args){
        ThreadDaemon td1 = new ThreadDaemon();
        ThreadDaemon td2 = new ThreadDaemon();
        
        td1.setName("康娜");
        td2.setName("雛鶴愛");
        
        td1.setDaemon(true);
        td2.setDaemon(true);
        
        td1.start();
        td2.start();
        
        Thread.currentThread().setName("jyh");
        for(int x =0;x<=5;x++){
   System.out.println(Thread.currentThread().getName()+":"+x);
        }
    }
}

中斷線程

package com.lianwei.Thread.ControlThread;
import java.util.Date;
public class ThreadStop extends Thread{
    public void run(){
        System.out.println("開始執(zhí)行:"+new Date());
        //我要休息10秒
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
//            e.printStackTrace();
            System.out.println("線程被終止了");
        }
        System.out.println("結(jié)束執(zhí)行:"+ new Date());
    }
}
package com.lianwei.Thread.ControlThread;
//public final void stop():讓線程停止睬辐,過時了挠阁,但還可以用
//public void interrupt():中斷線程宾肺。把線程的狀態(tài)終止,并拋出InterruptedException異常
public class ThreadStopDemo {
    public static void main(String[] args){
        ThreadStop ts = new ThreadStop();
        ts.start();
        //超過3秒不好侵俗,你就完了
        try {
            Thread.sleep(3000);
            //ts.stop();
            ts.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

鎖锨用,同步代碼塊,同步方法

同步機制(鎖機制)

同步代碼塊

格式:
synchronized(鎖對象){
需要同步的代碼
}

  • 作用:
    保證在某一時刻只會有一個線程在執(zhí)行同步代碼塊中的代碼
  • 鎖對象:
    可以是任意對象隘谣,但是操作相同資源的鎖對象必須是同一個增拥。
  • 解釋:
    線程只有拿到了鎖對象,才能執(zhí)行同步代碼塊中的代碼寻歧。換言之掌栅,這里的代碼如果執(zhí)行了,說明該線程拿到了鎖對象码泛,其他線程就不能拿到該鎖對象猾封。

同步方法

  • 同步方法:
    加了synchronized關(guān)鍵字修飾的方法。
  • 鎖對象:
    非靜態(tài)方法的鎖對象是:this對象噪珊。
    靜態(tài)方法的鎖對象是:當前類的字節(jié)碼文件對象晌缘。(類名.class)
    public synchronized void show(){}
    public static synchronized void show(){}
  • 什么時候用
    什么時候用同步代碼塊,什么時候用同步方法卿城?
    盡可能用同步代碼塊(被同步的內(nèi)容越少越好)
    如果一個方法內(nèi)的所有代碼都被同步代碼塊包住了枚钓,那就用同步方法就可以了

同步的好處及弊端

  • 好處:解決了多線程的安全問題
  • 弊端:因為每個線程去判斷同步上的鎖,這降低程序的運行效率會

死鎖

死鎖原因總結(jié)
線程1自身拿著一個鎖:A鎖瑟押,線程2自身拿著一個鎖:B鎖
當線程1要用B鎖搀捷,線程B要用A鎖的時候就會發(fā)生死鎖

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市多望,隨后出現(xiàn)的幾起案子嫩舟,更是在濱河造成了極大的恐慌,老刑警劉巖怀偷,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件家厌,死亡現(xiàn)場離奇詭異,居然都是意外死亡椎工,警方通過查閱死者的電腦和手機饭于,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來维蒙,“玉大人掰吕,你說我怎么就攤上這事÷” “怎么了殖熟?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長斑响。 經(jīng)常有香客問我菱属,道長钳榨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任纽门,我火速辦了婚禮薛耻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘膜毁。我一直安慰自己昭卓,他們只是感情好,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布瘟滨。 她就那樣靜靜地躺著,像睡著了一般能颁。 火紅的嫁衣襯著肌膚如雪杂瘸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天伙菊,我揣著相機與錄音败玉,去河邊找鬼。 笑死镜硕,一個胖子當著我的面吹牛运翼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兴枯,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼血淌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了财剖?” 一聲冷哼從身側(cè)響起悠夯,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎躺坟,沒想到半個月后沦补,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡咪橙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年夕膀,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片美侦。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡产舞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出音榜,到底是詐尸還是另有隱情庞瘸,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布赠叼,位于F島的核電站擦囊,受9級特大地震影響违霞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞬场,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一买鸽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贯被,春花似錦眼五、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至幌陕,卻和暖如春诵姜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搏熄。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工棚唆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人心例。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓宵凌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親止后。 傳聞我的和親對象是個殘疾皇子瞎惫,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

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

  • 進程和線程 進程 所有運行中的任務(wù)通常對應(yīng)一個進程,當一個程序進入內(nèi)存運行時,即變成一個進程.進程是處于運行過程中...
    小徐andorid閱讀 2,808評論 3 53
  • 本文主要講了java中多線程的使用方法、線程同步坯门、線程數(shù)據(jù)傳遞微饥、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等古戴。 首先講...
    李欣陽閱讀 2,454評論 1 15
  • Java多線程學習 [-] 一擴展javalangThread類 二實現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,957評論 1 18
  • 該文章轉(zhuǎn)自:http://blog.csdn.net/evankaka/article/details/44153...
    加來依藍閱讀 7,353評論 3 87
  • 10個技巧靠別計算機小白 一臺電腦是有許許多多零部件組成欠橘,只有這些零部件組合在一起協(xié)調(diào)工作,才能稱之為電腦现恼。電...
    星寰Helen閱讀 210評論 0 0