線程安全的誤解: 線程安全並不是否定資源共享

  • 原文:點擊打開鏈接

  • 之所以造成這個誤解,大概跟線程安全的幾種解決手段有關.
目前公認的幾種線程安全的解決手段:
  1. 同步技術
  2. 多用方法內局部變量
  3. ThreadLocal技術(一線程,一實例變量copy)
除同步技術外,另兩種解決手段都是"anti_sharing",實際是犧牲了多併發線程下的資源的共享特性.


  • 線程安全的定義:
多線程的共享資源的實際值會和理論值不一致,這樣就叫作"線程不安全"
多線程對共享資源的改變,也是理論值之一.即理論上是接受共享資源被多個線程改變的.

  • 舉例如下:
我們舉最常見的"多線程售票"的例子,很多人在學習多線程都是從這個例子開始的.
下面這段程序是存在線程安全問題的,但"共享售票"並不意味着線程不安全
public class MyThread implements Runnable {
    private int ticket = 5; // 一共才5張票,會被多線程共同賣出

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

    public static void main(String[] args) {
        MyThread mt = new MyThread(); // 單實例
        new Thread(mt).start() ;    // 一個線程開始賣票
        new Thread(mt).start() ;    // 另一個線程開始賣票
        new Thread(mt).start() ;    // 再一個線程開始賣票
    }
執行:
賣票:ticket = 5
賣票:ticket = 4
賣票:ticket = 3
賣票:ticket = 2
賣票:ticket = 1

因爲程序執行太快了,來不及顯性產生線程安全問題,我們在run()中加一個Thread.sleep(300)方法
    public void run() {
        for (int i = 0; i < 50; i++) {
            if (this.ticket > 0) {
                try {
                    Thread.sleep(300);// 延遲
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("賣票:ticket = " + this.ticket--);
運行結果如下:
D:\java\source\thread\sync>java syndemo.SynDemo01
賣票:ticket = 5
賣票:ticket = 4
賣票:ticket = 3
賣票:ticket = 2
賣票:ticket = 1
賣票:ticket = 0
賣票:ticket = -1              這就是理論值(this.ticket > 0)實際值(-1)不符,
                               反映了線程安全的概念定義
原因:
當剩最後一張票時
上一個進程通過了(this.ticket > 0)的判斷,卻sleep了,沒來得及把this.ticket--
而另一個進程趁機也通過了(this.ticket > 0)的判斷
這樣就形成了ticket=1時兩個線程都通過測試,都進行了--,就出現了-1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章