線程安全分析-局部變量-暴露引用

class ThreadSafe {
    public void method1(int loopNumber){
        ArrayList<Object> list = new ArrayList<>();
        for (int i = 0; i < loopNumber; i++) {
            method2(list);
            method3(list);
        }
    }

    private void method2(ArrayList<Object> list){
        list.add("1");
    }

    private void method3(ArrayList<Object> list){
        list.remove(0);
    }

   
}

第一個問題:method2和method3都是private,其方法引用的list對象,會不會暴露給外部?

答案是不會的;

答案是不會的,因爲method1裏創建出的list對象,在method2裏,沒有別的線程可以調用到了,所以method2所用的list對象,,一定是從method1中傳過去的,method3同理;

方法訪問修飾符帶來的思考,如果把method2和method3的方法修改爲public會不會產生線程安全問題?

情況1: 有其他線程調用method2和method3,會如何

class ThreadSafe {
    public void method1(int loopNumber){
        ArrayList<Object> list = new ArrayList<>();
        for (int i = 0; i < loopNumber; i++) {
            method2(list);
            method3(list);
        }
    }

    public void method2(ArrayList<Object> list){
        list.add("1");
    }

    public void method3(ArrayList<Object> list){
        list.remove(0);
    }

   
}

答案是沒有問題,因爲線程1調用method1創建了list對象,線程2調用method2傳進來的list參數,可能是線程1創建的list對象參數麼,這是不可能的,因此也沒有線程安全的問題;

class ThreadSafe {
    public void method1(int loopNumber){
        ArrayList<Object> list = new ArrayList<>();
        for (int i = 0; i < loopNumber; i++) {
            method2(list);
            method3(list);
        }
    }

    public void method2(ArrayList<Object> list){
        list.add("1");
    }

    public void method3(ArrayList<Object> list){
        list.remove(0);
    }

    static class ThreadSafeSubClass extends ThreadSafe{
        @Override
        public void method3(ArrayList<Object> list){
            new Thread(()->{
                list.remove(0);
            }).start();
        }
    }
}

情況2: 在情況1的基礎上,爲ThreadSafe類添加子類,子類覆蓋method2或method3方法,即將其中method2和method3方法修飾符改爲public後,list引用的對象會不會暴露給外部?

答案是會有影響的,因爲線程1調用method1生成list對象後,method2傳入此list對象,到達method3方法調用時候,子類生成了一個新的線程來訪問list對象,也就是說子類和父類共享了list對象資源;會有線程安全 問題;因爲你不能控制子類的行爲;

運行結果:

Exception in thread "Thread-3919" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
	at java.util.ArrayList.rangeCheck(ArrayList.java:653)
	at java.util.ArrayList.remove(ArrayList.java:492)
	at com.cuiwjava.test.ThreadSafeSubClass.lambda$method3$0(TestThreadSafe.java:42)
	at java.lang.Thread.run(Thread.java:748)
Disconnected from the target VM, address: '127.0.0.1:0', transport: 'socket'

Process finished with exit code 0

結論:方法的訪問修飾符是有意義的,private是可以保護方法的線程安全的,限制了子類不能覆蓋它;

將method3訪問修飾符改成private就OK了;另外建議將method1加上final,防止公共方法被子類影響

符合面向對象編程中:開閉原則中close,不想讓子類改變我的行爲;

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