Java多線程,Thread和Runnable究竟該用哪個__Java

來源:互聯網
上載者:User

       很久沒寫部落格了,內心有一絲罪惡感。其中一個原因是最近做的一些東西不適合在部落格上公開。

       今天抽空來說說Java多線程中的一個小話題,也是新人經常會遇到的。起因是我在給新人找培訓資料的時候,在網上看到了很多Thread和Runnable究竟該用哪個的討論,絕大多數這類文章都是同一個祖師爺的,都用了視窗賣票的例子。以下地址是一篇比較有代表性的(搞笑的是連Runnable都拼錯了):

http://www.oschina.net/question/565065_86563

 

       可見新人們在網上找到的資料都是些這種東西,真讓人憂慮啊。這篇博文槽點太多,我就不一一噴了,我們來把這篇認為正確的“最終寫法”拿出來實際編一編試試(我做了一處小改動,因為原始寫法線程還有死迴圈問題,另外把票數從100張改到了10張,便於分析)。

class ThreadTest implements Runnable {private int tickets = 10;public void run() {while (true) {if (tickets > 0) {System.out.println(Thread.currentThread().getName()+ " is saling ticket " + tickets--);} else {break;}}}}public class ThreadDemo1 {public static void main(String[] args) {ThreadTest t = new ThreadTest();new Thread(t).start();new Thread(t).start();new Thread(t).start();}}

       初看運行結果是正常的,3個視窗賣10張票。可是多運行幾次問題就來了,可能我臉比較黑,只跑了4遍就遇到了一次這樣的結果:

Thread-0 is saling ticket 10

Thread-0 is saling ticket 8

Thread-2 is saling ticket 9

Thread-2 is saling ticket 6

Thread-1 is saling ticket 10

Thread-1 is saling ticket 4

Thread-2 is saling ticket 5

Thread-2 is saling ticket 2

Thread-2 is saling ticket 1

Thread-0 is saling ticket 7

Thread-1 is saling ticket 3

 

       是的,編號10的票被賣了2次。為什麼會這樣,相信對多線程有瞭解的程式員都應該知道,--操作符內部的實現並不是原子的。解決方案很簡單,一是用synchronized這種內建鎖,二是用AtomicInteger這樣的concurrent包裡封裝好的元素,簡潔起見我用第二種實現如下:

import java.util.concurrent.atomic.AtomicInteger;//public class MyThread extends Thread {  //兩種寫法一樣public class MyThread implements Runnable{     private AtomicInteger tickets = new AtomicInteger(10);     @Override    public void run() {        while (true) {        int ticketnum;            if ((ticketnum = tickets.getAndDecrement()) > 0) {                System.out.println(Thread.currentThread().getName() + " is saling ticket: "                        + ticketnum);            } else {            break;            }        }    }    public static void main(String[] args) {         MyThread mt = new MyThread();        Thread t1 = new Thread(mt, "Win1");        Thread t2 = new Thread(mt, "Win2");        Thread t3 = new Thread(mt, "Win3");         t1.start();        t2.start();        t3.start();    }}

       以上代碼還說明一個問題,這類博文中說的“Runnable可以用來在多線程間共用對象,而Thread不能共用對象”,純屬無稽之談,Thread本身就實現了Runnable,不會導致能不能共用對象這種區別。兩者最大(甚至可以說唯一,因為其他差異對新人來說無關緊要)的區別是Thread是類而Runnable是介面,至於用類還是用介面,取決於繼承上的實際需要。

       最後回答標題的問題:Thread和Runnable究竟該用哪個。我的建議是都不用。因為Java這門語言發展到今天,在語言層面提供的多線程機制已經比較豐富且進階,完全不用線上程層面操作。直接使用Thread和Runnable這樣的“裸線程”元素比較容易出錯,還需要額外關注線程數等問題。建議:

       簡單的多線程程式,使用Executor。

       簡單的多線程,但不想關注線程層面因素,又熟悉Java8的:使用Java8的並行流,它底層基於ForkJoinPool,還能享受函數式編程的快捷。

       複雜的多線程程式,使用一個Actor庫,首推Akka。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.