天天看點

線程安全

什麼是線程安全,個人線上程中使用共享資源時,能夠保證共享資源在任何時候都是原子的、一緻的,這樣的線程就是線程安全的線程

首先來介紹一下共享資源的類型(這是我自己分類的,為了後文好解釋),共享資源從其類型可以分為三類(下文講到變量一律指類變量或執行個體變量,不再特别指出):

1.      獨立的基本類型共享資源,如一個簡單的int變量,例:

public classCls1 {

       private int a;

       public int getA(){return a;}

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

}

可以看到a沒有任何依賴。

public classCls2{

       private int b;

       private int c;

       // 沒有對a的通路方法,a在Cls外不可見。

假設上面類中b、c都不依賴a,則a是這種類型。

2.      互相依賴的基本類型共享資源,一個類中的幾個基本類型變量互相依賴,但從對象設計的角度又不能單獨把這幾個變量設計成一個類。

假設上例Cls2中的b、c互相依賴,則屬此種情況。

3.      64位的基本類型變量。這個比較特殊,因為某些機器上64變量會分成兩個32位的操作,是以和1不一樣。如double、long類型。

4.      類類型的共享資源。如下例中的obj:

public classCls3{

       private SomeObj obj;

public classSomeObj{

       其次來看看什麼是原子性、一緻性。其實在這裡我借用了事務ACID屬性的A和C,熟悉的朋友就不用我廢話了。所謂原子性,是指一個共享資源的所有屬性在任何時刻都是一起變化、密不可分的;所謂一緻性,是指一個共享資源的所有屬性在變化之後一定會達到一個一緻的狀态。

       最後根據上述四種共享資源類型,來看看如何做到線程安全。

1.      不用做什麼,隻一個獨立的變量,任何時候它都是原子、一緻的。

2.      使用synchronized關鍵字,保證幾個變量被一起修改、一起讀取。

3.      使用volatile關鍵字,然後就和1一樣了。

4.      和2一樣處理。

當對通路共享資源的方法不同時使用synchronized關鍵字時,是什麼樣一種情況呢?這是需要特别注意的,這樣不能保證線程安全!看看下面例子的運作結果就知道了(自己運作啊,我不貼結果了):

/**

 * $Author: $

 * $Date: $

 * $Revision: $

 * $History: $

 *

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

 */

public class TestThread extends Thread {

  private int a = 0;

  private int b = 0;

  public static voidmain(String[] args) {

    TestThread test = newTestThread();

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

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

      thread.start();

    }

  }

  public synchronized voiddoWrite() {

    a++;

    try {

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

    catch(InterruptedException e) {

    b++;

  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 useFile | Settings | File Templates.

      doWrite();

      print();

  public synchronized voidstart() {

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

ThreadLocal?ThreadLocal對于線程安全還是很有用的,如果資源不是共享的,那麼應該使用ThreadLocal,但如果确實需要線上程間共享資源,ThreadLocal就沒有用了!

最後,來一個完整的線程安全的例子:

  private int a = 0; //獨立的共享資源

  private int b = 0; //b、c互相依賴

  private int c = 0;

  private volatile long d =0L; //64位

//  private SomeObj obj = newSomeObj(); //對象類型,大家自己寫吧,我就不寫了。

    c++;

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

  public synchronized voidprint() {

   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;

      setA(i);

     System.out.println(getA());

      setD(18456187413L * i);

      System.out.println(getD());

寫的比較匆忙,如果有錯誤,還請大家指正,謝謝!

繼續閱讀