Runnable實現類的成員變量之線程安全問題


一. 先上結論

  • 當多個線程共用一個Runnable實現類的對象numRunnable時(Thread thread = new Thread(numRunnable,"thread"+i)),Runnable實現類的成員變量是線程不安全的!

二. 問題復現

public class Test {
    public static void main(String[] args) {
       int total = insertDataToTN(100,1);
       System.out.println("總:"+total); // 輸出結果(每次結果不一樣):427775

    }

    public static int insertDataToTN(int threadCount, final int cycleCount){

        class NumRunnable implements Runnable{
            int totalSum = 0;

            public void run(){
                for(int i = 0 ; i<10000;i++){
                    totalSum++;
                }
            }

        }

        NumRunnable numRunnable = new NumRunnable();
        List<Thread> threads = new ArrayList<Thread>();
        for(int i=0;i<threadCount;i++) {
            Thread thread = new Thread(numRunnable,"thread"+i);
            thread.start();
            threads.add(thread);
        }

        for(Thread tThread:threads){
            try {
                tThread.join();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return numRunnable.totalSum;
    }
}

三. 解決方法

1. 法1:使用原子類AtomicInteger

public class Test {
    public static void main(String[] args) {
        AtomicInteger a = insertDataToTN(100,1);
        System.out.println(a); // 輸出結果:1000000
    }

    public static AtomicInteger insertDataToTN(int threadCount, final int cycleCount){

        class NumRunnable implements Runnable{
            AtomicInteger totalSum = new AtomicInteger(0);

            public void run(){
                for(int i = 0 ; i<10000;i++){
                    totalSum.addAndGet(1);
                }
            }
        }

        NumRunnable numRunnable = new NumRunnable();
        List<Thread> threads = new ArrayList<Thread>();
        for(int i=0;i<threadCount;i++) {
            Thread thread = new Thread(numRunnable,"thread"+i);
            thread.start();
            threads.add(thread);
        }

        for(Thread tThread:threads){
            try {
                tThread.join();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        return numRunnable.totalSum;
    }
}

2. 法2:使用synchronized關鍵字

public class Test {
    public static void main(String[] args) {
        int total = insertDataToTN(100,1);
        System.out.println("總:"+total); // 輸出結果:1000000
    }

    public static int insertDataToTN(int threadCount, final int cycleCount){

        class NumRunnable implements Runnable{
             int totalSum = 0;

            public void run(){
                for(int i = 0 ; i<10000;i++){
                    add();
                }
            }

            public synchronized void add(){
                totalSum++;
            }

        }

        NumRunnable numRunnable = new NumRunnable();
        List<Thread> threads = new ArrayList<Thread>();
        for(int i=0;i<threadCount;i++) {
            Thread thread = new Thread(numRunnable,"thread"+i);
            thread.start();
            threads.add(thread);
        }

        for(Thread tThread:threads){
            try {
                tThread.join();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        return numRunnable.totalSum;

    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章