Java多線程-線程安全


1. 數據不共享的情況

在探討數據共享的話題前,先來看看數據不共享的情況,每一個線程里面的數據都是獨立的,就像下面的例子,3個線程,每一個線程自己對自己的數據進行扣減,直到0為止

public class TestThread {
    public static void main(String[] args) {

        MyThread myThread_A = new MyThread("A");
        MyThread myThread_B = new MyThread("B");
        MyThread myThread_C = new MyThread("C");

        myThread_A.start();
        myThread_B.start();
        myThread_C.start();

    }

}

class MyThread extends Thread {

    private int count = 5;
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        // super.run();

        while (count != 0) {
            System.out.println(name + " = " + count);
            count--;
        }
    }
}

 

運行結果:

 

2. 數據共享的情況

這里有一段測試代碼,看看共享數據的結構,按照理想的情況下,MyRunnable只實例了一次,所以里面的count=5將會被扣減5次,打印的結果應該是,5,4,3,2,1,因為這里有5個線程,每次調用run的時候,都會減去1,但是結果,確實有點出乎意外....而且每一次執行的結果都不一樣

public class TestThread {
    public static void main(String[] args) {

        //新建一個帶有Runnable接口的類
        MyRunnable myRunnable = new MyRunnable();

        //新建5個線程,但使用了同一個Runnable實例對象,意味着里面的數據是共享的
        //這里的Thread(Runnable,String)是一個構造函數,第一次參數為Runnable接口,第二個為線程名稱
        Thread thread_A = new Thread(myRunnable,"A");
        Thread thread_B = new Thread(myRunnable,"B");
        Thread thread_C = new Thread(myRunnable,"C");
        Thread thread_D = new Thread(myRunnable,"D");
        Thread thread_E = new Thread(myRunnable,"E");

        thread_A.start();
        thread_B.start();
        thread_C.start();
        thread_D.start();
        thread_E.start();

    }

}

class MyRunnable implements Runnable {

    private int count = 5;

    public MyRunnable() {
    }

    @Override
    public void run() {
        // super.run();
        System.out.println("當前線程名稱" + Thread.currentThread().getName() + " = " + count);
        count--;

    }
}

 

運行結果1:

 

運行結果2:

 

 

運行結果3:

 

 

3.線程不安全

經過上面的例子隱身出了一個問題,就是線程安全問題,在實際場景當中,這是一個非常危險的問題,例如在雙11,秒殺,活動中,很多買家同時在0點的時候按購買,但貨品只有1個,很明顯這里就是多線程處理同一個數據(貨品庫存量),那如果在線程不安全的情況下,會出現更上面例子一樣的情況,兩個人同一時間都在對同一個數字進行處理,結果有可能是,多名買家同時獲得這個商品。

為什么這樣呢,主要原因是count--這個代碼,一般情況,這行代碼做了3個動作

  1. 獲取count當前的值
  2. 對count的值進行-1的動作
  3. 對count重新賦值

那問題很明顯就出在第一步,假如A線程運行到這一行代碼獲取到count的值為5,接下來,B線程搶到CPU的使用前,他也執行到了這行代碼,獲取count的值也是5,因為A線程還沒有進行-1的操作

 

4.線程安全

那怎么辦呢,關鍵字synchronized,在run方法前加上這句的代碼就可以達到排隊執行方法的作用了,意思就是說,在執行run代碼的時候,線程先查看當前代碼塊有沒有鑰匙,如果有鑰匙,即可進入這扇門(代碼塊),然后執行里面的內容,執行完之后就會把鑰匙交出來,由下一個搶到鑰匙的人進入,並執行里面的內容。在這個搶鑰匙的過程中是人人平等,誰先搶到鑰匙,誰先進入。我們叫這塊區域“互斥區”。

class MyRunnable implements Runnable {

    private int count = 5;

    public MyRunnable() {
    }

    @Override
    synchronized public void run() {
        // super.run();
        System.out.println("當前線程名稱" + Thread.currentThread().getName() + " = " + count);
        count--;

    }
}

 

運行結果1:

 

運行結果2:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM