文章目錄
- 臨界資源
- 線程安全
- 基本概念
- *何謂競態條件*
- *何謂線程安全*
- 對象的安全
- 局部基本類型變量
- 局部的對象引用
- 對象成員(成員變量)
- 不可變性
臨界資源
臨界資源是一次僅允許一個進程使用的共享資源。各進程采取互斥的方式,實現共享的資源稱作臨界資源。屬于臨界資源的硬件有,打印機,磁帶機等;軟件有消息隊列,變量,數組,緩沖區等。諸進程間采取互斥方式,實現對這種資源的共享。
線程安全
基本概念
何謂競態條件
當兩個線程競爭同一資源時,如果對資源的訪問順序敏感,就稱存在競態條件。
導致競態條件發生的代碼區稱作臨界區。
在臨界區中使用適當的同步就可以避免競態條件,如使用synchronized或者加鎖機制。
何謂線程安全
允許被多個線程同時執行的代碼稱作線程安全的代碼。線程安全的代碼不包含競態條件。
對象的安全
局部基本類型變量
局部變量存儲在線程自己的棧中。也就是說,局部變量永遠也不會被多個線程共享。所以,基礎類型的
局部變量是線程安全的。下面是基礎類型的局部變量的一個例子:
public class ThreadTest {public static void main(String[]args){MyThread share = new MyThread();for (int i=0;i<50;i++){new Thread(share,"線程"+i).start();}}
}
class MyThread implements Runnable{public void run() {int a =0;++a;System.out.println(Thread.currentThread().getName()+":"+a);}
}
無論多少個線程對run()方法中的基本類型a執行++a操作,只是更新當前線程棧的值,不會影響其他線程,也就是不共享數據;
局部的對象引用
對象的局部引用和基礎類型的局部變量不太一樣,盡管引用本身沒有被共享,但引用所指的對象并沒有存儲在線程的棧內。所有的對象都存在共享堆中。
如果在某個方法中創建的對象不會逃逸出(即該對象不會被其它方法獲得,也不會被非局部變量引用到)該方法,那么它就是線程安全的。
實際上,哪怕將這個對象作為參數傳給其它方法,只要別的線程獲取不到這個對象,那它仍是線程安全的。
public void method1(){LocalObject localObject = new LocalObject();localObject.callMethod();method2(localObject);
}
public void method2(LocalObject localObject){localObject.setValue("value");
}
對象成員(成員變量)
對象成員存儲在堆上。如果兩個線程同時更新同一個對象的同一個成員,那這個代碼就不是線程安全的。
public class ThreadTest {public static void main(String[]args){NotThreadSafe sharedInstance = new NotThreadSafe();new Thread(new MyRunnable(sharedInstance)).start();new Thread(new MyRunnable(sharedInstance)).start();}
}
class MyRunnable implements Runnable{NotThreadSafe instance = null;public MyRunnable(NotThreadSafe instance){this.instance = instance;}public void run(){this.instance.add(" "+Thread.currentThread().getName());System.out.println(this.instance.builder.toString());}
}
class NotThreadSafe{StringBuilder builder = new StringBuilder();public void add(String text){this.builder.append(text);}
}
不可變性
通過創建不可變的共享對象來保證對象在線程間共享時不會被修改,從而實現線程安全。如下示例:
public class ImmutableValue{private int value = 0;public ImmutableValue(int value){this.value = value;}public int getValue(){return this.value;}
}
請注意ImmutableValue類的成員變量 value 是通過構造函數賦值的,并且在類中沒有set方法。這意味著一旦ImmutableValue實例被創建, value 變量就不能再被修改,這就是不可變性。但你可以通過getValue()方法讀取這個變量的值。