Java 多線程之 Runnable VS Thread 以及資源共享問(wèn)題

對(duì)于 Java 多線程編程中的 implements Runnable 與 extends Thread,部分同學(xué)可能會(huì)比較疑惑缨称,它們之間究竟有啥區(qū)別和聯(lián)系呢?他們是不是沒(méi)啥區(qū)別隨便選呢藐握?實(shí)際中究竟該選擇哪一個(gè)呢额各?

圖1

甚至網(wǎng)上不少博客文章以訛傳訛得出不少謬論,那今天的走進(jìn)科學(xué)欄目將帶您一一揭開(kāi)謎底酒贬。

1又憨、區(qū)別:

其實(shí)這塊主要是圍繞著接口和抽象類(lèi)的區(qū)別以及一些設(shè)計(jì)原則而言的。

**1.1 ****Inheritance Option **:

The limitation with "extends Thread" approach is that if you extend Thread, you can not extend anything else . Java does not support multiple inheritance. In reality , you do not need Thread class behavior , because in order to use a thread you need to instantiate one anyway. On the other hand, Implementing the Runnable interface gives you the choice to extend any class you like , but still define behavior that will be run by separate thread.

**1.2 ****Reusability **:

In "implements Runnable" , we are creating a different Runnable class for a specific behavior job (if the work you want to be done is job). It gives us the freedom to reuse the specific behavior job whenever required. "extends Thread" contains both thread and job specific behavior code. Hence once thread completes execution , it can not be restart again.

**1.3 ****Object Oriented Design **:

Implementing Runnable should be preferred . It does not specializing or modifying the thread behavior . You are giving thread something to run. We conclude that Composition is the better way. Composition means two objects A and B satisfies has-a relationship. "extends Thread" is not a good Object Oriented practice.

**1.4 ****Loosely-coupled **:

"implements Runnable" makes the code loosely-coupled and easier to read . Because the code is split into two classes . Thread class for the thread specific code and your Runnable implementation class for your job that should be run by a thread code. "extends Thread" makes the code tightly coupled . Single class contains the thread code as well as the job that needs to be done by the thread.

**1.5 ****Functions overhead **:

"extends Thread" means inheriting all the functions of the Thread class which we may do not need . job can be done easily by Runnable without the Thread class functions overhead.

至此锭吨,個(gè)人是推薦優(yōu)先選擇 implements Runnable 蠢莺。

2、聯(lián)系:

2.1 其實(shí)Thread類(lèi)也是Runnable接口的子類(lèi)

public class Thread extends Object implements Runnable

2.2 啟動(dòng)線程都是 start() 方法

追蹤Thread中的start()方法的定義零如,可以發(fā)現(xiàn)此方法中使用了private native void start0();其中native關(guān)鍵字表示可以調(diào)用操作系統(tǒng)的底層函數(shù)躏将,這樣的技術(shù)稱(chēng)為JNI技術(shù)(java Native Interface)。

但是在使用Runnable定義的子類(lèi)中沒(méi)有start()方法考蕾,只有Thread類(lèi)中才有祸憋。此時(shí)觀察Thread類(lèi),有一個(gè)構(gòu)造方法:public Thread(Runnable targer)辕翰,此構(gòu)造方法接受Runnable的子類(lèi)實(shí)例夺衍,也就是說(shuō)可以通過(guò)Thread類(lèi)來(lái)啟動(dòng)Runnable實(shí)現(xiàn)的多線程。

2.3 網(wǎng)傳的一種繆論:用Runnable就可以實(shí)現(xiàn)資源共享喜命,而 Thread 不可以

有同學(xué)的例子是這樣的沟沙,參考: http://developer.51cto.com/art/201203/321042.htm

package tmp;

class MyThread extends Thread {

    private int ticket = 10;
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    public void run() {
        for (int i = 0; i < 500; i++) {
            if (this.ticket > 0) {
                System.out.println(this.name + "賣(mài)票---->" + (this.ticket--));
            }
        }
    }
}

public class ThreadDemo {

    public static void main(String[] args) {
        MyThread mt1 = new MyThread("一號(hào)窗口");
        MyThread mt2 = new MyThread("二號(hào)窗口");
        MyThread mt3 = new MyThread("三號(hào)窗口");
        mt1.start();
        mt2.start();
        mt3.start();
    }

}

// 一號(hào)窗口賣(mài)票---->10
// 二號(hào)窗口賣(mài)票---->10
// 二號(hào)窗口賣(mài)票---->9
// 二號(hào)窗口賣(mài)票---->8
// 三號(hào)窗口賣(mài)票---->10
// 三號(hào)窗口賣(mài)票---->9
// 三號(hào)窗口賣(mài)票---->8
...

Runnable 代碼:

package tmp;

class MyThread1 implements Runnable {
    private int ticket = 10;
    private String name;

    public void run() {
        for (int i = 0; i < 500; i++) {
            if (this.ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "賣(mài)票---->" + (this.ticket--));
            }
        }
    }
}

public class RunnableDemo {

    public static void main(String[] args) {
        MyThread1 mt = new MyThread1();
        Thread t1 = new Thread(mt, "一號(hào)窗口");
        Thread t2 = new Thread(mt, "二號(hào)窗口");
        Thread t3 = new Thread(mt, "三號(hào)窗口");
        t1.start();
        t2.start();
        t3.start();
    }

}

// 二號(hào)窗口賣(mài)票---->10
// 三號(hào)窗口賣(mài)票---->9
// 三號(hào)窗口賣(mài)票---->7
// 一號(hào)窗口賣(mài)票---->9
// 三號(hào)窗口賣(mài)票---->6
// 二號(hào)窗口賣(mài)票---->8
// 三號(hào)窗口賣(mài)票---->4
// 一號(hào)窗口賣(mài)票---->5
// 三號(hào)窗口賣(mài)票---->2
// 二號(hào)窗口賣(mài)票---->3
// 一號(hào)窗口賣(mài)票---->1

由此差別,有同學(xué)就得出了一個(gè)結(jié)論:用Runnable就可以實(shí)現(xiàn)資源共享壁榕,而 Thread 不可以矛紫,這是他們的主要差別之一。牌里。颊咬。

其實(shí)仔細(xì)看看代碼就知道务甥,這只是兩種寫(xiě)法的區(qū)別,根本就不是 implements Runnable 與 extends Thread 的區(qū)別:

MyThread1 mt = new MyThread1();  
Thread t1 = new Thread(mt,"一號(hào)窗口");  
Thread t2 = new Thread(mt,"二號(hào)窗口");  
Thread t3 = new Thread(mt,"三號(hào)窗口"); 
////////////////
Thread t1 = new Thread(new MyThread1(),"一號(hào)窗口");  
Thread t2 = new Thread(new MyThread1(),"二號(hào)窗口");  
Thread t3 = new Thread(new MyThread1(),"三號(hào)窗口");

其實(shí)喳篇,想要“資源共享”敞临,Thread 也可以做到的:

private static int ticket = 10;

// 三號(hào)窗口賣(mài)票---->10
// 一號(hào)窗口賣(mài)票---->9
// 二號(hào)窗口賣(mài)票---->9
// 一號(hào)窗口賣(mài)票---->7
// 一號(hào)窗口賣(mài)票---->5
// 三號(hào)窗口賣(mài)票---->8
// 一號(hào)窗口賣(mài)票---->4
// 二號(hào)窗口賣(mài)票---->6
// 一號(hào)窗口賣(mài)票---->2
// 三號(hào)窗口賣(mài)票---->3
// 二號(hào)窗口賣(mài)票---->1

通過(guò) static 就可以實(shí)現(xiàn)擁有共同的ticket=10,但問(wèn)題也來(lái)了麸澜,你會(huì)發(fā)現(xiàn)一二號(hào)窗口都賣(mài)了第 9 張票挺尿。

3、資源共享帶來(lái)的問(wèn)題:多線程的線程安全問(wèn)題

上面的例子以及結(jié)果證明了多線程場(chǎng)景下炊邦,需要留意線程安全的問(wèn)題:

3.1 同步run()方法

public synchronized void run()

3.2 同步 class 對(duì)象

synchronized (Test.class)

3.3 同步某些靜態(tài)對(duì)象

private static final Object countLock = new Object();
synchronized (countLock) {
    count++;
}

3.4 最后給個(gè)完整的例子编矾,模擬在線售票與查詢(xún):

package tmp;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

public class Demo implements Runnable {
    String name;
    //  static Integer tickets = 20;
    private static AtomicInteger tickets = new AtomicInteger(20);

    public Demo(String name) {
        this.name = name;
    }

    public void run() {
        for (int i = 1; i <= 20; i++) {
            synchronized (tickets) {
                if (tickets.get() > 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                    System.out.println("我取票第" + ": " + tickets.getAndDecrement() + " 張票。");
                    //                  tickets--;
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                    System.out.println("==========現(xiàn)在查詢(xún)還剩" + ": " + tickets.get() + " 張票馁害。");
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        Demo demo = new Demo("hello");
        new Thread(demo).start();
        new Thread(demo).start();
        new Thread(demo).start();
    }
}

到這兒窄俏,本期走進(jìn)科學(xué)也要跟大家說(shuō)聲再見(jiàn)了,其實(shí)聊著聊著感覺(jué)都快跑題了碘菜,多線程這塊話題很多凹蜈,很復(fù)雜,需要慢慢實(shí)踐與積累忍啸,祝大家玩的愉快踪区。

歡迎關(guān)注微信公眾號(hào):java大牛愛(ài)好者

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市吊骤,隨后出現(xiàn)的幾起案子缎岗,更是在濱河造成了極大的恐慌,老刑警劉巖白粉,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件传泊,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鸭巴,警方通過(guò)查閱死者的電腦和手機(jī)眷细,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鹃祖,“玉大人溪椎,你說(shuō)我怎么就攤上這事√窨冢” “怎么了校读?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)祖能。 經(jīng)常有香客問(wèn)我歉秫,道長(zhǎng),這世上最難降的妖魔是什么养铸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任雁芙,我火速辦了婚禮轧膘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘兔甘。我一直安慰自己谎碍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布洞焙。 她就那樣靜靜地躺著椿浓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闽晦。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天提岔,我揣著相機(jī)與錄音仙蛉,去河邊找鬼。 笑死碱蒙,一個(gè)胖子當(dāng)著我的面吹牛荠瘪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赛惩,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼哀墓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了喷兼?” 一聲冷哼從身側(cè)響起篮绰,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎季惯,沒(méi)想到半個(gè)月后吠各,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勉抓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年贾漏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藕筋。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纵散,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出隐圾,到底是詐尸還是另有隱情伍掀,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布暇藏,位于F島的核電站硕盹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏叨咖。R本人自食惡果不足惜瘩例,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一啊胶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧垛贤,春花似錦焰坪、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至善绎,卻和暖如春黔漂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背禀酱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工炬守, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人剂跟。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓减途,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親曹洽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鳍置,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

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

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,332評(píng)論 0 10
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)送淆,斷路器税产,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 早上好!#幸福實(shí)修#~每天進(jìn)步1%#幸福實(shí)修10班@王華玉--永康 201708(22/30) 【幸福三朵玫瑰】 ...
    王華玉閱讀 191評(píng)論 1 0
  • 利立浦的學(xué)術(shù)偷崩,法律砖第,風(fēng)俗,教育等方面环凿,作者詳細(xì)地介紹了許多梧兼。從此足以可見(jiàn),利立普象征的是那時(shí)的英國(guó)智听。政治紊...
    曹政陽(yáng)閱讀 187評(píng)論 0 5
  • 寫(xiě)在開(kāi)頭的話羽杰,是被餓醒的 糾結(jié)了半天要不要起來(lái)打開(kāi)冰箱找吃的,腦子里在不斷地搜索著冰箱到推。最終的答案考赛,有一罐紅牛,兩...
    山藥蛋Young閱讀 176評(píng)論 0 0