<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    潛魚(yú)在淵

    Concentrating on Architectures.

    posts - 77, comments - 309, trackbacks - 0, articles - 0
      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    Java線程安全精解

    Posted on 2005-11-17 01:59 非魚(yú) 閱讀(23417) 評(píng)論(37)  編輯  收藏 所屬分類(lèi): Java技術(shù)

    一直不敢寫(xiě)點(diǎn)什么,是因?yàn)閼?zhàn)戰(zhàn)兢兢,生怕寫(xiě)的不好甚至寫(xiě)錯(cuò)了會(huì)誤人子弟。隨筆可以隨便寫(xiě)一下,不用太過(guò)計(jì)較,可是技術(shù)從來(lái)都要不得半點(diǎn)馬虎,差之毫厘,謬以千里啊!但敝帚自珍又不是我的風(fēng)格,雖然文筆不好,也要勉為其難了。廢話少說(shuō),進(jìn)入正題。

     

           從我開(kāi)始接觸Java的多線程起就總是覺(jué)得書(shū)上講的不是那么清楚。不是說(shuō)讀完了不會(huì)寫(xiě),而是對(duì)寫(xiě)出來(lái)的多線程代碼懵懵懂懂,不知道每一句會(huì)有什么影響,心里感覺(jué)忐忑。后來(lái)仔細(xì)研讀Java語(yǔ)言規(guī)范后,才慢慢搞明白一些細(xì)節(jié)。我主要想說(shuō)的,也就是這些經(jīng)驗(yàn)吧。

     

           首先要搞清楚的是線程的共享資源,共享資源是多線程中每個(gè)線程都要訪問(wèn)的類(lèi)變量或?qū)嵗兞浚蚕碣Y源可以是單個(gè)類(lèi)變量或?qū)嵗兞浚部梢允且唤M類(lèi)變量或?qū)嵗兞俊6嗑€程程序可以有多個(gè)共享資源。下面描述他們之間的一對(duì)多關(guān)系(*表示多):

          

                         多線程程序(1----共享資源(*----類(lèi)變量或?qū)嵗兞浚?/span>1…*

     

    只有類(lèi)變量和實(shí)例變量可以成為共享資源,細(xì)分如下:

    1.       實(shí)現(xiàn)線程的類(lèi)(繼承Thread類(lèi)、實(shí)現(xiàn)Runnable接口的類(lèi))的類(lèi)變量、實(shí)例變量。

    2.       實(shí)現(xiàn)線程的類(lèi)的類(lèi)變量、實(shí)例變量的類(lèi)變量、實(shí)例變量,可以不規(guī)范的寫(xiě)為:TreadClass.ClassOrInstanceVar[.ClassOrInstanceVar]*[]*的內(nèi)容表示無(wú)限可重復(fù)。

    3.       不是實(shí)現(xiàn)線程的類(lèi),但其對(duì)象可能是線程的類(lèi)變量或?qū)嵗兞俊H?/span>ServletEJB。這些類(lèi)的類(lèi)變量和實(shí)例變量,不規(guī)范的寫(xiě)為:ServletOrEJB.ClassOrInstanceVar[.ClassOrInstanceVar]*

    4.       特別注意:局部變量、做為參數(shù)傳遞的非類(lèi)變量、非實(shí)例變量不是共享資源。

     

    那么什么是線程安全呢?關(guān)于這個(gè)問(wèn)題我在網(wǎng)上百度了一下(沒(méi)辦法,有時(shí)候GOOGLE用不了),發(fā)現(xiàn)不少人在問(wèn)這個(gè)問(wèn)題,也有不少錯(cuò)誤的理解。所以我給出一個(gè)較容易理解的解釋?zhuān)?strong>在線程中使用共享資源時(shí),能夠保證共享資源在任何時(shí)候都是原子的、一致的,這樣的線程就是線程安全的線程。還不太理解?沒(méi)有關(guān)系,慢慢解釋。

     

    首先來(lái)介紹一下共享資源的類(lèi)型(這是我自己分類(lèi)的,為了后文好解釋?zhuān)蚕碣Y源從其類(lèi)型可以分為三類(lèi)(下文講到變量一律指類(lèi)變量或?qū)嵗兞浚辉偬貏e指出):

    1.       獨(dú)立的基本類(lèi)型共享資源,如一個(gè)簡(jiǎn)單的int變量,例:

    public class Cls1 {

           private int a;

           public int getA(){return a;}

           public void setA(int a){this.a = a;}

    }

    可以看到a沒(méi)有任何依賴(lài)。

    public class Cls2{

           private int a;

           private int b;

           private int c;

           // 沒(méi)有對(duì)a的訪問(wèn)方法,aCls外不可見(jiàn)。

    }

    假設(shè)上面類(lèi)中bc都不依賴(lài)a,則a是這種類(lèi)型。

     

    2.       相互依賴(lài)的基本類(lèi)型共享資源,一個(gè)類(lèi)中的幾個(gè)基本類(lèi)型變量互相依賴(lài),但從對(duì)象設(shè)計(jì)的角度又不能單獨(dú)把這幾個(gè)變量設(shè)計(jì)成一個(gè)類(lèi)。

    假設(shè)上例Cls2中的bc互相依賴(lài),則屬此種情況。

    3.       64位的基本類(lèi)型變量。這個(gè)比較特殊,因?yàn)槟承C(jī)器上64變量會(huì)分成兩個(gè)32位的操作,所以和1不一樣。如doublelong類(lèi)型。

    4.       類(lèi)類(lèi)型的共享資源。如下例中的obj

    public class Cls3{

           private SomeObj obj;

    }

    public class SomeObj{

           private int a;

           private int b;

    }

     

           其次來(lái)看看什么是原子性、一致性。其實(shí)在這里我借用了事務(wù)ACID屬性的AC,熟悉的朋友就不用我廢話了。所謂原子性,是指一個(gè)共享資源的所有屬性在任何時(shí)刻都是一起變化、密不可分的;所謂一致性,是指一個(gè)共享資源的所有屬性在變化之后一定會(huì)達(dá)到一個(gè)一致的狀態(tài)。

     

           最后根據(jù)上述四種共享資源類(lèi)型,來(lái)看看如何做到線程安全。

     

    1.       不用做什么,只一個(gè)獨(dú)立的變量,任何時(shí)候它都是原子、一致的。

    2.       使用synchronized關(guān)鍵字,保證幾個(gè)變量被一起修改、一起讀取。

    3.       使用volatile關(guān)鍵字,然后就和1一樣了。

    4.       2一樣處理。

     

    當(dāng)對(duì)訪問(wèn)共享資源的方法不同時(shí)使用synchronized關(guān)鍵字時(shí),是什么樣一種情況呢?這是需要特別注意的,這樣不能保證線程安全!看看下面例子的運(yùn)行結(jié)果就知道了(自己運(yùn)行啊,我不貼結(jié)果了):

    /**

     * $Author: $

     * $Date: $

     * $Revision: $

     * $History: $

     *

     * Created by feelyou, at time 22:31:53, 2005-11-16.

     */

     

    public class TestThread extends Thread {

     

      private int a = 0;

      private int b = 0;

     

      public static void main(String[] args) {

        TestThread test = new TestThread();

        for (int i = 0; i < 10; i++) {

          Thread thread = new Thread(test, "thread-" + i);

          thread.start();

        }

      }

     

      public synchronized void doWrite() {

        a++;

        try {

          sleep((int)(Math.random()*100));

        }

        catch (InterruptedException e) {

        }

        b++;

        try {

          sleep((int)(Math.random()*100));

        }

        catch (InterruptedException e) {

        }

      }

     

      public void print() {

        System.out.println("" + Thread.currentThread().getName() + ":a:" + a);

        System.out.println("" + Thread.currentThread().getName() + ":b:" + b);

      }

     

      public void run() {

        super.run();    //To change body of overridden methods use File | Settings | File Templates.

        for (int i = 0; i < 10; i++) {

          doWrite();

          print();

        }

      }

     

      public synchronized void start() {

        super.start();    //To change body of overridden methods use File | Settings | File Templates.

      }

    }

     

    ThreadLocalThreadLocal對(duì)于線程安全還是很有用的,如果資源不是共享的,那么應(yīng)該使用ThreadLocal,但如果確實(shí)需要在線程間共享資源,ThreadLocal就沒(méi)有用了!

     

    最后,來(lái)一個(gè)完整的線程安全的例子:

    /**

     * $Author: $

     * $Date: $

     * $Revision: $

     * $History: $

     *

     * Created by feelyou, at time 22:31:53, 2005-11-16.

     */

     

    public class TestThread extends Thread {

     

      private int a = 0; //獨(dú)立的共享資源

      private int b = 0; //bc互相依賴(lài)

      private int c = 0;

      private volatile long d = 0L; //64

    //  private SomeObj obj = new SomeObj(); //對(duì)象類(lèi)型,大家自己寫(xiě)吧,我就不寫(xiě)了。

     

      public static void main(String[] args) {

        TestThread test = new TestThread();

        for (int i = 0; i < 10; i++) {

          Thread thread = new Thread(test, "thread-" + i);

          thread.start();

        }

      }

     

      public synchronized void doWrite() {

        b++;

        try {

          sleep((int)(Math.random()*100));

        }

        catch (InterruptedException e) {

        }

        c++;

        try {

          sleep((int)(Math.random()*100));

        }

        catch (InterruptedException e) {

        }

      }

     

      public synchronized void print() {

        System.out.println("" + Thread.currentThread().getName() + ":b:" + b);

        System.out.println("" + Thread.currentThread().getName() + ":c:" + c);

      }

     

      private void setA(int a) {

          this.a = a;

      }

     

      private int getA() {

          return a;

      }

     

      public long getD() {

          return d;

      }

     

      public void setD(long d) {

          this.d = d;

      }

     

      public void run() {

        super.run();    //To change body of overridden methods use File | Settings | File Templates.

        for (int i = 0; i < 10; i++) {

          doWrite();

          print();

          setA(i);

          System.out.println(getA());

          setD(18456187413L * i);

          System.out.println(getD());

        }

      }

     

      public synchronized void start() {

        super.start();    //To change body of overridden methods use File | Settings | File Templates.

      }

    }

    寫(xiě)的比較匆忙,如果有錯(cuò)誤,還請(qǐng)大家指正,謝謝!

    評(píng)論

    # re: Java線程安全詳解  回復(fù)  更多評(píng)論   

    2005-12-16 10:44 by www
    什么詳解啊 胡說(shuō)八到,

    # re: Java線程安全詳解  回復(fù)  更多評(píng)論   

    2005-12-16 12:20 by 非魚(yú)
    寫(xiě)的比較匆忙,如果有錯(cuò)誤,還請(qǐng)大家指正。

    可能還不夠詳細(xì)吧,但是哪里胡說(shuō)八道了?拜托,如果有錯(cuò)誤請(qǐng)明確指出好不好?

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2006-01-19 00:36 by aaa
    還可以呀。呵呵。有用

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2006-01-24 15:53 by 路過(guò)..
    還不錯(cuò).是我見(jiàn)過(guò)少數(shù)描述線程安全沒(méi)有什么錯(cuò)誤理解的文章..
    使用同步比較容易造成性能影響甚至死瑣情況,
    簡(jiǎn)單的辦法就是共享的類(lèi)不使用實(shí)例變量,都改用局部變量.
    當(dāng)一個(gè)單例的類(lèi)有實(shí)例變量時(shí)就要小心他很可能不是線程安全的了.

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2006-02-27 20:54 by mrwjx
    沒(méi)看懂,關(guān)于 “共享資源的類(lèi)型” 這一段,能用更通俗的話講一下嗎,我看了好幾遍,還是不明白您的意思,另外關(guān)于線程安全簡(jiǎn)單的講,是不是可以理解成多個(gè)線程調(diào)用線程安全的類(lèi)的方法的話,不會(huì)出現(xiàn)不可預(yù)知的不正常的情況

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2006-04-10 19:20 by java愛(ài)好者
    既然你害怕寫(xiě)東西,就不要寫(xiě)了吧,你的思維思路是沒(méi)錯(cuò)的,但是你的表達(dá)很不清晰,很容易給初學(xué)者造成迷茫困惑,呵呵,以后多寫(xiě)點(diǎn)代碼吧

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2006-07-11 15:15 by mn
    樓上的真是sb

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2006-08-13 09:03 by loocky
    寫(xiě)的其實(shí)不錯(cuò)

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2006-08-27 23:12 by happy
    人家好心好意寫(xiě)出來(lái)與大家分享,大家應(yīng)該支持一下啊!
    有問(wèn)題認(rèn)真討論,出口傷人就太不應(yīng)該了。

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2006-12-10 10:35 by lyl
    不錯(cuò),謝謝,辛苦了

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2007-03-31 23:32 by xzw
    寫(xiě)的真的很不錯(cuò)的,謝謝了

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2007-06-24 22:46 by 肖建
    你雞兒屎的,寫(xiě)的還不錯(cuò),
    你對(duì)JAVA的線程安全已經(jīng)理解的很不錯(cuò)了,
    我很佩服你哈,
    你是不是搞了很久這方面的東西了啊,
    不然是沒(méi)有這么深厚的功底的哈

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2007-06-28 16:25 by sinkos
    我很欣賞這位作者:一直不敢寫(xiě)點(diǎn)什么,是因?yàn)閼?zhàn)戰(zhàn)兢兢,生怕寫(xiě)的不好甚至寫(xiě)錯(cuò)了會(huì)誤人子弟。隨筆可以隨便寫(xiě)一下,不用太過(guò)計(jì)較,可是技術(shù)從來(lái)都要不得半點(diǎn)馬虎,差之毫厘,謬以千里啊!
    這些話體現(xiàn)作者一絲不茍的態(tài)度,科學(xué)的態(tài)度.
    謝謝你,謝謝這位作者!

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2007-07-07 09:53 by itkui
    謝謝樓主分享。

    我感覺(jué)罵人是不對(duì)的,尤其沒(méi)有仔細(xì)看完就匆匆罵人的同志。

    哪里好哪里不好,你說(shuō)出來(lái)嗎。

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2007-09-17 16:14 by 同聲傳譯
    愿意將自己的勞動(dòng)成果與別人分享其實(shí)就已經(jīng)很不錯(cuò)了。

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2007-09-28 11:04 by 大王
    不錯(cuò)。支持。

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2008-05-18 13:54 by 極地冰冷
    寫(xiě)的不錯(cuò),

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2008-08-26 09:09 by yp
    不錯(cuò)

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2008-08-26 18:25 by 陳堯
    -,還不錯(cuò)啦.雖然沒(méi)看得很懂但是我覺(jué)得還是滿仔細(xì)的.
    那些講粗話的同志是不是要思考一下自己的素質(zhì)呢?..

    # re: Java線程安全精解[未登錄](méi)  回復(fù)  更多評(píng)論   

    2008-09-19 08:50 by caoer
    純支持,繼續(xù)努力,共勉……

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2008-10-24 18:10 by xxyw
    看的不是很明白..不過(guò)謝謝樓主了..

    # re: Java線程安全精解[未登錄](méi)  回復(fù)  更多評(píng)論   

    2008-11-17 17:23 by XXX
    還不錯(cuò)

    # re: Java線程安全精解[未登錄](méi)  回復(fù)  更多評(píng)論   

    2008-11-25 01:12 by fbysss
    ---實(shí)現(xiàn)線程的類(lèi)(繼承Thread類(lèi)、實(shí)現(xiàn)Throwable接口的類(lèi))
    是不是寫(xiě)錯(cuò)了?應(yīng)該是Runnable接口吧?

    另外<!--[if !supportLists]--> 這些是啥?模板標(biāo)簽沒(méi)替換呢?重新排一下版吧,看上去比較費(fèi)勁

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2009-01-13 18:30 by 讀鐵人
    你的第一個(gè)例子的那個(gè)結(jié)果確實(shí)是不同步的,不過(guò)你知道為什么嗎?寫(xiě)數(shù)據(jù)和輸出數(shù)據(jù)的方法不是同步的,盡管你加了synchronized,但是run方法里面沒(méi)有加吧? public synchronized void f()
    {
    for (int i = 0; i < 10; i++) {

    doWrite();

    print();

    }
    }
    然后在run方法里面調(diào)用f()就行了。這就是原子性。
    共享資源簡(jiǎn)單點(diǎn)講就是線程要共用的變量,一般就是類(lèi)變量,那像你說(shuō)的怎么復(fù)雜。線程安全就是要保證原子性,你什么時(shí)候看你start方法前面要加synchronized的?

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2009-01-13 18:34 by 讀鐵人
    如果你覺(jué)得我說(shuō)的不對(duì),可以來(lái)csdn找我,cy729215495,我也是絕不輕易發(fā)貼,誤人子弟。我在blogjava沒(méi)有注冊(cè),729215495也是我的qq號(hào)碼,可以交流。

    # re: Java線程安全精解[未登錄](méi)  回復(fù)  更多評(píng)論   

    2009-02-11 16:02 by jade
    不錯(cuò)

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2009-03-16 20:02 by ee
    e

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2009-04-17 16:42 by weii
    還是要支持一下樓主啊!幸苦了,罵人的能寫(xiě)出來(lái)嗎?

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2009-07-12 11:15 by 絕對(duì)路過(guò)
    Google"線程安全 JAVA"一下,這是第一篇。

    # re: Java線程安全精解[未登錄](méi)  回復(fù)  更多評(píng)論   

    2009-09-07 17:30 by qq
    我想說(shuō)的是這個(gè)繼承了Thread類(lèi)的線程不會(huì)出現(xiàn)問(wèn)題嗎

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2009-09-08 10:38 by 亂碼(luan.ma(a)163.com)
    來(lái)批批“4. 特別注意:局部變量、做為參數(shù)傳遞的非類(lèi)變量、非實(shí)例變量不是共享資源。”

    void f(Object key)
    {
    Person person;
    if (map.contains(key)) {
    person = map.get(key);
    }
    else {
    person = new Person();
    map.put(key, person);
    }

    synchronized (person) {
    ...
    //對(duì) person 的一些操作
    ...
    }
    }

    LZ請(qǐng)看以上代碼

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2009-11-06 10:46 by remox
    共享資源什么的 要考慮java的內(nèi)存模型吧

    理論上所有資源都可以成為共享資源,實(shí)際情況也的確如此

    但有些資源是無(wú)法不成為共享資源,是必然的共享資源,比如靜態(tài)變量

    這里就涉及到線程工作棧和主存的同步,

    那對(duì)于每個(gè)線程自身的存儲(chǔ)區(qū)域又是如何分配的呢

    究竟Java的內(nèi)存模型在多線程環(huán)境中是如何進(jìn)行對(duì)資源的管理的。

    你說(shuō)的這些距離精解還是不夠的啊

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2009-11-25 10:09 by ddy
    看的出來(lái)lz很用心,先謝謝lz了。
    也許是因?yàn)閘z一直都“戰(zhàn)戰(zhàn)兢兢”,少有這么公開(kāi)表達(dá)觀點(diǎn),乃至表達(dá)不清。就這篇文章,我作為初學(xué)者看起來(lái)很吃力,在表達(dá)方式、條理性上lz還可以有改進(jìn)。
    再次謝謝lz

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2009-12-11 11:32 by 路過(guò)
    你的第一個(gè)例子的那個(gè)結(jié)果確實(shí)是不同步的,不過(guò)你知道為什么嗎?寫(xiě)數(shù)據(jù)和輸出數(shù)據(jù)的方法不是同步的,盡管你加了synchronized,但是run方法里面沒(méi)有加吧? public synchronized void f()
    {
    for (int i = 0; i < 10; i++) {

    doWrite();

    print();

    }
    }
    然后在run方法里面調(diào)用f()就行了。這就是原子性。
    共享資源簡(jiǎn)單點(diǎn)講就是線程要共用的變量,一般就是類(lèi)變量,那像你說(shuō)的怎么復(fù)雜。線程安全就是要保證原子性,你什么時(shí)候看你start方法前面要加synchronized的?
    說(shuō)得太好了

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2010-08-27 12:27 by 7510
    你這個(gè)也敢叫精解?!
    不要誤人子弟了
    趕緊把文章刪了
    還列g(shù)oogle第一條呢

    # re: Java線程安全精解[未登錄](méi)  回復(fù)  更多評(píng)論   

    2011-02-12 10:57 by jeff
    寫(xiě)得很不錯(cuò),比一般人寫(xiě)得好多 了.樓主是真會(huì)的人.頂

    # re: Java線程安全精解  回復(fù)  更多評(píng)論   

    2011-04-06 15:54 by su30mmkx
    文中
    “1. 不用做什么,只一個(gè)獨(dú)立的變量,任何時(shí)候它都是原子、一致的。”
    反省一下是不是有問(wèn)題。 本人覺(jué)得這種情況下也不是線程安全的。
    主站蜘蛛池模板: 亚洲色婷婷六月亚洲婷婷6月| 午夜免费福利在线观看| 黄色网址免费大全| 亚洲乱码一二三四五六区| 亚洲精品~无码抽插| 亚洲天天做日日做天天看| 亚洲人成综合网站7777香蕉| 久久亚洲AV成人无码国产电影| 免费人妻精品一区二区三区| 亚洲一区二区三区在线| 亚洲s码欧洲m码吹潮| 亚洲日韩精品无码专区加勒比| 日本系列1页亚洲系列| 成人无码区免费A∨直播| 久久久久久精品成人免费图片| 国产成人精品免费久久久久| 日韩大片免费观看视频播放| 热99RE久久精品这里都是精品免费 | 国产偷窥女洗浴在线观看亚洲| 四虎影在线永久免费观看| 亚洲日韩欧洲无码av夜夜摸| 亚洲日本在线播放| 免费精品国自产拍在线播放| 99re6热视频精品免费观看| 久久国产乱子伦精品免费看| 成人免费网站在线观看| 亚洲啪啪综合AV一区| 亚洲H在线播放在线观看H| 精品一区二区三区免费视频| 亚洲精品黄色视频在线观看免费资源 | 99爱在线精品免费观看| 亚洲成a人在线看天堂无码| 国产无遮挡色视频免费视频| 亚洲国产精品SSS在线观看AV| 亚洲真人无码永久在线观看| 亚洲人成网站18禁止| 成人性做爰aaa片免费看| 女人张开腿给人桶免费视频| 免费国产作爱视频网站| 夫妻免费无码V看片| 国产亚洲av片在线观看播放|