실패한volatile 검증

3054 단어
방금 새 회사에 와서 프로젝트에서 대량으로 사용되는 이중 검사 자물쇠 방식의 단례를 발견했지만 이상하게도volatile 수식어를 넣지 않았다.volatile 매개 변수를 진지하게 복습해 보았는데, 이것은 확실히 추가할 필요가 있다는 것을 발견하였다.그런데 과연volatile를 넣지 않으면 문제가 생기지 않을까요?
이미 알고 있는 이해에 따라 new의 새로운 대상이 나타날 때 원자 조작이 나타납니다.
4
  • 메모리 공간을 할당합니다

  • 4
  • 초기화 대상

  • 4
  • 메모리 공간의 주소를 대응하는 인용에 부여한다

  • volatile 파라미터를 사용하지 않으면 1-3-2의 실행 순서가 나타날 수 있습니다. 그러면 instance==null을 판단할 때 instance가 비어 있지 않고 instance로 되돌아갈 수 있습니다. 그러나 실제로 이 instance는 여전히null입니다.volatile이라는 인자를 사용하면 정렬을 금지합니다. 상기 과정은 1-2-3의 순서에 따라 실행됩니다.그리고 나서 나는 CountDownLatch를 사용하여 높은 병발을 시뮬레이션해서 instance==null이null인 상황이 나타날지 테스트했다.
    유감스럽게도 맥에 2000개의 라인을 추가하여 동시에 깨우기 (실제로는 이렇게 많지 않다. cpu가 제한되어 있기 때문에) 안드로이드는 300개의 라인을 동시에 깨우기 위해 여러 번 반복했지만 null로 나타나지 않았다.
    옆에 기술이 좋은 동료와 이야기를 나눴는데 이런 상황은 높은 서버(cpu 멀티코어)를 설정하고 대량으로 병발할 때 나타날 수 있다. 안드로이드나 나 나 같은 저조맥에서 나타날 확률이 비교적 적다고 생각했다.
    실패한 테스트라고 할 수 있겠지.기록해.참고 사항: 논의 사항 파악
    테스트 클래스 첨부:
    public class Singleton {
        //  volatile 
        private static Singleton instance;
    
        private Singleton() {
        }
    
        // 
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    
    
        public static void main(String[] args) {
            init();
        }
    
    
        /**
         *  
         */
        public static final int THREAD_NUM = 1000;
    
        /**
         *  
         */
        private static long startTime = 0L;
        private static volatile int num = 0;
    
        public static void init() {
            try {
                startTime = System.currentTimeMillis();
                System.out.println("CountDownLatch started at: " + startTime);
    
                //  1
                CountDownLatch countDownLatch = new CountDownLatch(1);
    
                for (int i = 0; i < THREAD_NUM; i++) {
                    new Thread(new Run(countDownLatch)).start();
                }
                //  
                countDownLatch.countDown();
            } catch (Exception e) {
                System.out.println("Exception: " + e);
            }
        }
    
        /**
         *  
         */
        private static class Run implements Runnable {
            private final CountDownLatch startLatch;
    
            public Run(CountDownLatch startLatch) {
                this.startLatch = startLatch;
            }
    
            @Override
            public void run() {
                try {
                    //  
                    startLatch.await();
    
                    //  
                    Singleton instance = getInstance();
                    if (instance == null) {
                        System.out.print("Thread.currentThread() =" + Thread.currentThread().getId() + (instance == null ? "instance = null" : " " + "
    ")); } // num = num + 1; // System.out.print("num = " + num + "
    "); } catch (Exception e) { e.printStackTrace(); } } } }

    좋은 웹페이지 즐겨찾기