java——多線程講解二

多線程是多個(gè)線程同時(shí)對同一個(gè)數(shù)據(jù)執(zhí)行相同或不同的任務(wù)。要注意的是囤躁,這樣的操作很大可能會出現(xiàn)線程安全問題冀痕,和線程死鎖問題。
現(xiàn)介紹一下為什么要用同步線程:

public class MyThread implements Runnable {
    private int ticket=10;
    @Override
    public void run() {
       for(int i=0;i<10;i++){
           if(this.ticket>0){
             try {
                 Thread.sleep(100);
             } catch (InterruptedException e) {
                e.printStackTrace();
             }     
             System.out.println(Thread.currentThread().getName()+"正在出售倒數(shù)第:"+this.ticket--+"張票");
           }
       }
    }
}
單多個(gè)線程訪問同一個(gè)對象是狸演,會出現(xiàn)其中一條線程執(zhí)行業(yè)務(wù)代碼的時(shí)候言蛇,CPU的執(zhí)行權(quán)被另一條線程搶走了,通過上面代碼可以明顯看出輸出了負(fù)數(shù)宵距,這和我們現(xiàn)實(shí)生活是完全不存在的腊尚。這就是線程安全問題

這使得我們需要通過靜態(tài)化ticket,或者是用同步線程來實(shí)現(xiàn)我們要的功能满哪。

下面先介紹一下怎么解決線程安全問題的實(shí)現(xiàn)婿斥;
方式一:可以使用同步代碼塊來實(shí)現(xiàn)。
示例:

public class MyThread implements Runnable {
    private int ticket=10;
    @Override
    public synchronized void run() {
       for(int i=0;i<10;i++){
           if(this.ticket>0){
             try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }      
             System.out.println(Thread.currentThread().getName()+"正在出售倒數(shù)第:"+this.ticket--+"張票");
           }
       }
    }
}

示例二:使用同步代碼塊來實(shí)現(xiàn)

public class MyThread implements Runnable {
    private int ticket=10;
    @Override
    public void run() {
       for(int i=0;i<10;i++){
            synchronized ("鎖"){
                  if(this.ticket>0){
             try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }      
                 System.out.println(Thread.currentThread().getName()+"正在出售倒數(shù)第:"+this.ticket--+"張票");
           }
       }
          }
           
    }
}

上面兩種方式都能實(shí)現(xiàn)代碼的同步翩瓜,
線程之所以能同步受扳,是因?yàn)榧恿艘粋€(gè)鎖對象,在使用同步函數(shù)的時(shí)候兔跌,鎖對象是對象本身this勘高,而在使用同步代碼塊的時(shí)候,鎖對象是自己定義的坟桅,可以是任何對象华望。
建議:要是用同步線程的時(shí)候,建議優(yōu)先使用同步代碼塊仅乓,因?yàn)橥酱a塊鎖對象是自己定義的赖舟,方便對鎖進(jìn)行操作。這個(gè)原因下面將要說到夸楣。

通過上面的代碼會發(fā)現(xiàn)宾抓,我在方法中使用了sleep方法子漩。sleep()方法是Thread類中的一個(gè)方法,為什么沒有把它放到上一節(jié)將石洗,是因?yàn)檫@個(gè)方法有點(diǎn)特殊幢泼。這個(gè)涉及到線程的各種狀態(tài):
線程開始的時(shí)候是創(chuàng)建狀態(tài):(new 對象的時(shí)候.)
當(dāng)調(diào)用了start方法的時(shí)候,線程處于可以運(yùn)行狀態(tài)讲衫,在這個(gè)狀態(tài)下的線程具備CPU的等待權(quán)缕棵,但是不具備CPU的執(zhí)行權(quán)。
當(dāng)線程執(zhí)行的時(shí)候他具備了CPU的執(zhí)行權(quán)涉兽。這個(gè)時(shí)候稱為運(yùn)行狀態(tài)招驴。
當(dāng)完成任務(wù)代碼塊的時(shí)候,線程死亡枷畏。
在可運(yùn)行狀態(tài)和運(yùn)行狀態(tài)之間還有一個(gè)狀態(tài)别厘,這個(gè)狀態(tài)稱為臨時(shí)阻塞狀態(tài)。進(jìn)入這個(gè)狀態(tài)需要調(diào)用sleep()或wait()方法矿辽。這個(gè)時(shí)候線程不具備CPU的等待資格丹允,和CPU的執(zhí)行權(quán)。
sleep()方法是自己設(shè)置阻塞時(shí)間袋倔。當(dāng)時(shí)間一到雕蔽,線程會自動轉(zhuǎn)換成可運(yùn)行狀態(tài)。他是Thread中的一個(gè)方法宾娜。當(dāng)一個(gè)線程在同步方法中調(diào)用了sleep方法批狐,其它線程不能調(diào)用它的其它同步方法。
swit()是Object中的一個(gè)方法前塔,當(dāng)線程調(diào)用了這個(gè)方法嚣艇。需要通過notify或者notifyAll方法來喚醒線程。線程阻塞是存放在線程池中的华弓。一個(gè)對象對應(yīng)一個(gè)線程池食零。
當(dāng)線程阻塞是,線程會自動釋放CPU的等待權(quán)和CPU的執(zhí)行權(quán)寂屏。但是如果使用的sleep方法贰谣,線程是不會釋放鎖對象的。而wait方法是會釋放鎖對象迁霎。
下面說下經(jīng)典的線程通訊:

//產(chǎn)品類
class Product{
    
    String name;  //名字
    
    double price;  //價(jià)格
    
    boolean flag = false; //產(chǎn)品是否生產(chǎn)完畢的標(biāo)識吱抚,默認(rèn)情況是沒有生產(chǎn)完成。
    
}

//生產(chǎn)者
class Producer extends Thread{
    
    Product  p ;    //產(chǎn)品
    
    public Producer(Product p) {
        this.p  = p ;
    }
    
    
    
    @Override
    public void run() {
        int i = 0 ; 
        while(true){
         synchronized (p) {
            if(p.flag==false){
                 if(i%2==0){
                     p.name = "蘋果";
                     p.price = 6.5;
                 }else{
                     p.name="香蕉";
                     p.price = 2.0;
                 }
                 System.out.println("生產(chǎn)者生產(chǎn)出了:"+ p.name+" 價(jià)格是:"+ p.price);
                 p.flag = true;
                 i++;
                 p.notifyAll(); //喚醒消費(fèi)者去消費(fèi)
            }else{
                //已經(jīng)生產(chǎn) 完畢考廉,等待消費(fèi)者先去消費(fèi)
                try {
                    p.wait();   //生產(chǎn)者等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
             
        }   
      } 
    }
}


//消費(fèi)者
class Customer extends Thread{
    
    Product p; 
    
    public  Customer(Product p) {
        this.p = p;
    }
    
    
    @Override
    public void run() {
        while(true){
            synchronized (p) {  
                if(p.flag==true){  //產(chǎn)品已經(jīng)生產(chǎn)完畢
                    System.out.println("消費(fèi)者消費(fèi)了"+p.name+" 價(jià)格:"+ p.price);
                    p.flag = false; 
                    p.notifyAll(); // 喚醒生產(chǎn)者去生產(chǎn)
                }else{
                    //產(chǎn)品還沒有生產(chǎn),應(yīng)該 等待生產(chǎn)者先生產(chǎn)秘豹。
                    try {
                        p.wait(); //消費(fèi)者也等待了...
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }   
    }
}

public class Demo5 {
    
    public static void main(String[] args) {
        Product p = new Product();  //產(chǎn)品
        //創(chuàng)建生產(chǎn)對象
        Producer producer = new Producer(p);
        //創(chuàng)建消費(fèi)者
        Customer customer = new Customer(p);
        //調(diào)用start方法開啟線程
        producer.start();
        customer.start();
        
        
    }
    
}

線程死鎖的體現(xiàn):

lass DeadLock extends Thread{
    
    public DeadLock(String name){
        super(name);
    }
    
    
    public void run() {
        if("張三".equals(Thread.currentThread().getName())){
            synchronized ("遙控器") {
                System.out.println("張三拿到了遙控器,準(zhǔn)備 去拿電池!!");
                synchronized ("電池") {
                    System.out.println("張三拿到了遙控器與電池了昌粤,開著空調(diào)爽歪歪的吹著...");
                }
            }
        }else if("狗娃".equals(Thread.currentThread().getName())){
            synchronized ("電池") { 
                System.out.println("狗娃拿到了電池既绕,準(zhǔn)備去拿遙控器!!");
                synchronized ("遙控器") {
                    System.out.println("狗娃拿到了遙控器與電池了啄刹,開著空調(diào)爽歪歪的吹著...");
                }
            }
            
        }   
    }
    
    
}

public class Demo2 {

    public static void main(String[] args) {
        DeadLock thread1 = new DeadLock("張三");
        DeadLock thread2 = new DeadLock("狗娃");
        //開啟線程
        thread1.start();
        thread2.start();
        
        
    }
    
}

死鎖現(xiàn)象出現(xiàn) 的根本原因:

  1. 存在兩個(gè)或者兩個(gè)以上的線程。
  2. 存在兩個(gè)或者兩個(gè)以上的共享資源岸更。

【注】講解可能有不足的地方鸵膏,希望各位小伙伴能幫我補(bǔ)充不足之處膊升,謝謝怎炊!
復(fù)制得來終覺淺,要想知道自己敲廓译!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末评肆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子非区,更是在濱河造成了極大的恐慌瓜挽,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件征绸,死亡現(xiàn)場離奇詭異久橙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)管怠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門淆衷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人渤弛,你說我怎么就攤上這事祝拯。” “怎么了她肯?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵佳头,是天一觀的道長。 經(jīng)常有香客問我晴氨,道長康嘉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任籽前,我火速辦了婚禮亭珍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘聚假。我一直安慰自己块蚌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布膘格。 她就那樣靜靜地躺著峭范,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瘪贱。 梳的紋絲不亂的頭發(fā)上纱控,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天辆毡,我揣著相機(jī)與錄音,去河邊找鬼甜害。 笑死舶掖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尔店。 我是一名探鬼主播眨攘,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嚣州!你這毒婦竟也來了鲫售?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤该肴,失蹤者是張志新(化名)和其女友劉穎情竹,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匀哄,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡秦效,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涎嚼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阱州。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖铸抑,靈堂內(nèi)的尸體忽然破棺而出贡耽,到底是詐尸還是另有隱情,我是刑警寧澤鹊汛,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布蒲赂,位于F島的核電站,受9級特大地震影響刁憋,放射性物質(zhì)發(fā)生泄漏滥嘴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一至耻、第九天 我趴在偏房一處隱蔽的房頂上張望若皱。 院中可真熱鬧,春花似錦尘颓、人聲如沸走触。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽互广。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惫皱,已是汗流浹背像樊。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旅敷,地道東北人生棍。 一個(gè)月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像媳谁,于是被迫代替她去往敵國和親涂滴。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

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