Java——Thread VS Runnable

一硬梁、線程創(chuàng)建的兩種方式

1.1繼承Thread

class MyThread extends Thread{
        @Override
        public void run() {
            
        }
    }
//創(chuàng)建線程
MyThread myThread = new MyThread();
//啟動線程
myThread.start();

1.2實現(xiàn)Runnable接口

class MyThread implements Runnable{

        @Override
        public void run() {
            
        }
    }
MyThread mt = new MyThread();
Thread td = new Thread(mt);
td.start();

1.3比較

  1. Runnable方式可以避免Thread方式由于Java單繼承特性帶來的缺陷
  2. Runnable的代碼可以被多個線程(Thread實例)共享味廊,適合于多個線程處理同一資源的情況

二编饺、賣火車票

2.1 Thread實現(xiàn)

public class TicketsThread {

    public static void main(String[] args) {
        MyThread myThread1 = new MyThread("一號窗口");
        MyThread myThread2 = new MyThread("二號窗口");
        MyThread myThread3 = new MyThread("三號窗口");
        
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }

}

class MyThread extends Thread{
    private int ticketsCont = 5 ;
    private String name;
    public MyThread(String name) {
        this.name = name;
    }
    
    @Override
    public void run() {
        while (ticketsCont > 0) {
            //有票就賣一張
            ticketsCont--;
            System.out.println(name+"賣了一張票,剩余票數(shù)為"+ ticketsCont);
        }
    }
}

運行結(jié)果

二號窗口賣了一張票艘儒,剩余票數(shù)為4
二號窗口賣了一張票,剩余票數(shù)為3
二號窗口賣了一張票,剩余票數(shù)為2
二號窗口賣了一張票咱枉,剩余票數(shù)為1
二號窗口賣了一張票,剩余票數(shù)為0
三號窗口賣了一張票徒恋,剩余票數(shù)為4
三號窗口賣了一張票蚕断,剩余票數(shù)為3
三號窗口賣了一張票,剩余票數(shù)為2
三號窗口賣了一張票入挣,剩余票數(shù)為1
三號窗口賣了一張票亿乳,剩余票數(shù)為0
一號窗口賣了一張票,剩余票數(shù)為4
一號窗口賣了一張票径筏,剩余票數(shù)為3
一號窗口賣了一張票葛假,剩余票數(shù)為2
一號窗口賣了一張票,剩余票數(shù)為1
一號窗口賣了一張票滋恬,剩余票數(shù)為0

結(jié)果并不能滿意聊训。沒有對票數(shù)這個多線程共同訪問的數(shù)據(jù)進行同步,使得每一個線程都有自己的一個數(shù)據(jù)源恢氯。

2.2Runnable實現(xiàn)

public class TicketsRunnable {

    public static void main(String[] args) {
        MyThread mThread = new MyThread();
        Thread thread1 = new Thread(mThread,"窗口1");
        Thread thread2 = new Thread(mThread,"窗口2");
        Thread thread3 = new Thread(mThread,"窗口3");
        
        thread1.start();
        thread2.start();
        thread3.start();
    }

}

class MyThread implements Runnable{
    private int ticketsCont = 5;
    
    @Override
    public void run() {
        while (ticketsCont > 0) {
            //有票就賣一張
            ticketsCont--;
            System.out.println(Thread.currentThread().getName()+"賣了一張票带斑,剩余票數(shù)為"+ ticketsCont);
        }
    }
}

運行結(jié)果

窗口1賣了一張票,剩余票數(shù)為4
窗口1賣了一張票勋拟,剩余票數(shù)為3
窗口3賣了一張票勋磕,剩余票數(shù)為1
窗口2賣了一張票,剩余票數(shù)為0
窗口1賣了一張票敢靡,剩余票數(shù)為2

仍然不能滿足要求挂滓,這種不符合常理的結(jié)果,沒有達到預想中的4 3 2 1 0
這就是線程的交互執(zhí)行導致的;舉個例子:
線程1先執(zhí)行賣了1張票,也即是票--1,現(xiàn)在票為4,但是這個線程還沒沒有來得及在控制臺打印出剩余多少票,線程又搶到了CPU資源執(zhí)行,線程2又把票--1;此時票為3,線程2輸出票就為3,線程2執(zhí)行完了后,線程1又再次獲得CPU資源,繼續(xù)把剛剛沒有輸出的話輸出,但是此時票已經(jīng)為3了,于是又輸出了3。
看過多線程的小伙伴應該不難理解,這就是線程不安全,想要保證輸出結(jié)果,可以使用synchronized關鍵字來解決

2.3 實現(xiàn)

public class TicketsRunnable {

    public static void main(String[] args) {
        MyThread mThread = new MyThread();
        Thread thread1 = new Thread(mThread,"窗口1");
        Thread thread2 = new Thread(mThread,"窗口2");
        Thread thread3 = new Thread(mThread,"窗口3");
        
        thread1.start();
        thread2.start();
        thread3.start();
    }

}

class MyThread implements Runnable {
    private int ticketsCont = 10;
    
    @Override
    public void run() {
        while (ticketsCont > 0) {
            //有票就賣一張
            synchronized (this) {
                if (ticketsCont > 0) {
                    ticketsCont--;
                    System.out.println(Thread.currentThread().getName()+"賣了一張票醋安,剩余票數(shù)為"+ ticketsCont);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        
    }
}

用同步鎖來實現(xiàn)杂彭,注意在鎖里也加入判斷語句,不然可能會出現(xiàn)線程1進入了while循環(huán)吓揪,然后被搶去了線程亲怠,最后賣出了51張票。

運行結(jié)果

窗口1賣了一張票柠辞,剩余票數(shù)為9
窗口3賣了一張票团秽,剩余票數(shù)為8
窗口3賣了一張票,剩余票數(shù)為7
窗口2賣了一張票,剩余票數(shù)為6
窗口2賣了一張票习勤,剩余票數(shù)為5
窗口2賣了一張票踪栋,剩余票數(shù)為4
窗口3賣了一張票,剩余票數(shù)為3
窗口3賣了一張票图毕,剩余票數(shù)為2
窗口1賣了一張票夷都,剩余票數(shù)為1
窗口3賣了一張票,剩余票數(shù)為0

三予颤、線程的生命周期

3.1 創(chuàng)建

Thread thd = new Thread();

3.2 就緒

start()被調(diào)用即進入就緒狀態(tài)囤官,線程被加入到了線程隊列中,等待CPU服務蛤虐,具備了運行的條件党饮,但不一定已經(jīng)開始運行了

3.3 運行

獲取到了CPU服務,執(zhí)行run()邏輯

3.4 阻塞

受到阻塞事件的影響驳庭,由于某種原因刑顺,讓出cpu資源,如sleep()方法

3.5 終止

run()執(zhí)行完畢

四饲常、守護線程

4.1 線程分類

  1. 用戶線程:
    看得到的蹲堂,主線程、連接網(wǎng)絡的子線程等不皆。
  2. 守護線程:
    運行在后臺贯城,為用戶線程服務熊楼。
    特點:一旦所有用戶線程結(jié)束運行霹娄,守護線程會隨著JVM一起結(jié)束工作。
    應用:數(shù)據(jù)庫連接池中的監(jiān)測線程 & JVM虛擬機啟動后的監(jiān)測線程 & 垃圾回收線程

4.2注意

  1. 在start()前調(diào)用方法 setDaemon(true)
  2. 守護線程中產(chǎn)生的新線程也是守護線程
  3. 不是所有的任務都可以分配給守護線程來執(zhí)行鲫骗,比如讀寫操作犬耻、邏輯運算。

4.3守護線程中進行讀寫操作

public class DaemonThreadDemo  {


    public static void main(String[] args) {
        System.out.println("進入主線程" + Thread.currentThread().getName());
        DaemonThread daemonThread = new DaemonThread();
        Thread thread = new Thread(daemonThread);
        thread.setDaemon(true);
        thread.start();
        
        Scanner scanner  = new Scanner(System.in);
        scanner.next();
        
        System.out.println("退出主線程" + Thread.currentThread().getName());
    }

}

class DaemonThread implements  Runnable {
    public void run() {
        System.out.println("程序進入了守護線程" + Thread.currentThread().getName());
        try {
            writeToFile();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("程序退出了守護線程" + Thread.currentThread().getName());
    }

    private void writeToFile() throws Exception {
        File file = new File("G:"+ File.separator+ "demo.txt");
        //true 追加操作执泰,不是覆蓋操作
        OutputStream os = new FileOutputStream(file,true);
        int count = 0;
        while (count < 999) {
            os.write(("\r\nword"+count).getBytes());
            System.out.println("守護線程"+ Thread.currentThread().getName()+"向文件中寫入了word"+ count++);
            Thread.sleep(1000);
        }
        os.close();
    }
}

運行結(jié)果

進入主線程main
程序進入了守護線程Thread-0
守護線程Thread-0向文件中寫入了word0
守護線程Thread-0向文件中寫入了word1
守護線程Thread-0向文件中寫入了word2
8
退出主線程main

守護線程未正常退出

原文鏈接:Thread與Runnable比較

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末枕磁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子术吝,更是在濱河造成了極大的恐慌计济,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件排苍,死亡現(xiàn)場離奇詭異沦寂,居然都是意外死亡,警方通過查閱死者的電腦和手機淘衙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門传藏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事毯侦】蘧福” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵侈离,是天一觀的道長试幽。 經(jīng)常有香客問我,道長卦碾,這世上最難降的妖魔是什么抡草? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮蔗坯,結(jié)果婚禮上康震,老公的妹妹穿的比我還像新娘。我一直安慰自己宾濒,他們只是感情好腿短,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绘梦,像睡著了一般橘忱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卸奉,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天钝诚,我揣著相機與錄音,去河邊找鬼榄棵。 笑死凝颇,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的疹鳄。 我是一名探鬼主播拧略,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼瘪弓!你這毒婦竟也來了垫蛆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤腺怯,失蹤者是張志新(化名)和其女友劉穎袱饭,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呛占,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡虑乖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了栓票。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片决左。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡愕够,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出佛猛,到底是詐尸還是另有隱情惑芭,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布继找,位于F島的核電站遂跟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏婴渡。R本人自食惡果不足惜幻锁,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望边臼。 院中可真熱鬧哄尔,春花似錦、人聲如沸柠并。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽臼予。三九已至鸣戴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粘拾,已是汗流浹背窄锅。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缰雇,地道東北人入偷。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像寓涨,于是被迫代替她去往敵國和親盯串。 傳聞我的和親對象是個殘疾皇子氯檐,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

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

  • Java多線程學習 [-] 一擴展javalangThread類 二實現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,952評論 1 18
  • 本文主要講了java中多線程的使用方法戒良、線程同步、線程數(shù)據(jù)傳遞冠摄、線程狀態(tài)及相應的一些線程函數(shù)用法糯崎、概述等。 首先講...
    李欣陽閱讀 2,444評論 1 15
  • 下面是我自己收集整理的Java線程相關的面試題河泳,可以用它來好好準備面試沃呢。 參考文檔:-《Java核心技術 卷一》-...
    阿呆變Geek閱讀 14,757評論 14 507
  • 寫在前面的話: 這篇博客是我從這里“轉(zhuǎn)載”的,為什么轉(zhuǎn)載兩個字加“”呢拆挥?因為這絕不是簡單的復制粘貼薄霜,我花了五六個小...
    SmartSean閱讀 4,715評論 12 45
  • 桌上的菜還很多某抓,春曉吃完飯,可小余的飯沒怎么動惰瓜。問小余:“你怎么不吃否副?”小余眼鏡都不抬一下,冷冷地說:“我不餓崎坊”纲鳎”...
    追光小強閱讀 133評論 1 1