Android-多線程安全問題-synchronized


先看一個售票案例Demo,多線程程序對共享數據操作引發的安全問題:

package android.java.thread09;

/**
 * 售票線程
 */
class Booking implements Runnable {

    /**
     * 模擬票的總算 10張票
     */
    private int ticket = 10;

    @Override
    public void run() {

        while (true) {

            if (ticket > 0) {
                // 讓線程在這里停一下,會更加容易復現線程的安全問題,就算不加這行代碼,安全問題依然有
                try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }

                System.out.println("名稱:" + Thread.currentThread().getName() + "窗口賣出第" + ticket + "張票");
                ticket--;
            }

        }

    }
}

/**
 * 售票案例
 */
public class BookingTest {

    public static void main(String[] args) {

        /**
         * 定義Runnable實現類Booking,此實現類Booking不是線程,此實現類Booking給四個Thread去執行的
         */
        Runnable booking = new Booking();

        // 實例化線程對象
        Thread thread1 = new Thread(booking); // 此實現類Booking給Thread去執行的
        Thread thread2 = new Thread(booking); // 此實現類Booking給Thread去執行的
        Thread thread3 = new Thread(booking); // 此實現類Booking給Thread去執行的
        Thread thread4 = new Thread(booking); // 此實現類Booking給Thread去執行的

        // 開啟啟動線程
        thread1.start(); // 啟動第Thread-0窗口 執行賣票任務
        thread2.start(); // 啟動第Thread-1窗口 執行賣票任務
        thread3.start(); // 啟動第Thread-2窗口 執行賣票任務
        thread4.start(); // 啟動第Thread-3窗口 執行賣票任務


    }

}

 

打印的日志結果,注意:⚠️ 沒有打印的日志結果都不同,這是CPU對線程非常快速的切換造成的,哪個線程先有執行權 就執行哪個線程 都是隨機的

名稱:Thread-0窗口賣出第10張票
名稱:Thread-3窗口賣出第9張票
名稱:Thread-1窗口賣出第8張票
名稱:Thread-2窗口賣出第7張票
名稱:Thread-0窗口賣出第6張票
名稱:Thread-3窗口賣出第5張票
名稱:Thread-2窗口賣出第4張票
名稱:Thread-1窗口賣出第4張票
名稱:Thread-2窗口賣出第2張票
名稱:Thread-0窗口賣出第1張票
名稱:Thread-3窗口賣出第1張票
名稱:Thread-1窗口賣出第-1張票
名稱:Thread-2窗口賣出第-2張票

 

CPU的隨機性,到底切換到哪個線程,到底執行哪個線程代碼的多少行,等等,都是隨機的

 

 

分析原因,為什么會出現以上日志打印的各個情況呢,為什么會出現 0張票 -1張票   這種情況呢?,看以下CPU執行線程的隨機性就明白了

 


 

 

通過以上畫圖分析原因,造成安全問題的有以下兩個因素: 

  1.線程任務中,發現有共享數據,例如:ticket。

  2.多線程操作共享數據,例如:ticket。

造成的原因是:Thread-0在對共享數據操作過程中,CPU執行了Thread-1對共享數據操作,   相當於:我在數錢,突然我出去有事了,然后有個人拿了500塊錢,等我在回來數錢的時候,就已經發生是數據安全問題

 


 

 

 

解決多線程安全問題,synchronize 加同步代碼塊,同步代碼塊:synchronize{ 操作共享數據的代碼 }

 

 

package android.java.thread09;

/**
 * 售票線程
 */
class Booking implements Runnable {

    /**
     * 模擬票的總算 10張票
     */
    private int ticket = 10;

    @Override
    public void run() {

        while (true) {

            /**
             * 加入了同步代碼塊的代碼synchronized,
             * 不管CPU如何瘋狂的切換執行,
             * 只要同步代碼塊里面的代碼沒有執行完,
             * 就不准其他線程進來執行
             * 這樣就保證了多線程操作共享數據的安全新
             */
            synchronized (Booking.class) { // 同步操作共享數據的代碼

                if (ticket > 0) {

                    // 讓線程在這里停一下,會更加容易復現線程的安全問題,就算不加這行代碼,安全問題依然有
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("名稱:" + Thread.currentThread().getName() + "窗口賣出第" + ticket + "張票");
                    ticket--;
                }
            }

        }

    }
}

/**
 * 售票案例
 */
public class BookingTest {

    public static void main(String[] args) {

        /**
         * 定義Runnable實現類Booking,此實現類Booking不是線程,此實現類Booking給四個Thread去執行的
         */
        Runnable booking = new Booking();

        // 實例化線程對象
        Thread thread1 = new Thread(booking); // 此實現類Booking給Thread去執行的
        Thread thread2 = new Thread(booking); // 此實現類Booking給Thread去執行的
        Thread thread3 = new Thread(booking); // 此實現類Booking給Thread去執行的
        Thread thread4 = new Thread(booking); // 此實現類Booking給Thread去執行的

        // 開啟啟動線程
        thread1.start(); // 啟動第Thread-0窗口 執行賣票任務
        thread2.start(); // 啟動第Thread-1窗口 執行賣票任務
        thread3.start(); // 啟動第Thread-2窗口 執行賣票任務
        thread4.start(); // 啟動第Thread-3窗口 執行賣票任務


    }

}

以下日志結果,是CPU隨機執行到哪個線程,就哪個線程打印,CPU執行線程的隨機性很重要

以下日志結果,是CPU隨機執行到哪個線程,就哪個線程打印,CPU執行線程的隨機性很重要

以下日志結果,是CPU隨機執行到哪個線程,就哪個線程打印,CPU執行線程的隨機性很重要

 

.........

 


免責聲明!

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



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