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張票java

 

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

 

 

分析緣由,爲何會出現以上日誌打印的各個狀況呢,爲何會出現 0張票 -1張票   這種狀況呢?,看如下CPU執行線程的隨機性就明白了

 


 

 

經過以上畫圖分析緣由,形成安全問題的有如下兩個因素: 

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

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

形成的緣由是:Thread-0在對共享數據操做過程當中,CPU執行了Thread-1對共享數據操做,   至關於:我在數錢,忽然我出去有事了,而後有我的拿了500塊錢,等我在回來數錢的時候,就已經發生是數據安全問題ide

 


 

 

 

解決多線程安全問題,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執行線程的隨機性很重要

 

.........spa

相關文章
相關標籤/搜索