>

다음 배열을 선언했다고 가정합니다 :

private final int[] array = new int[10];

이제 각각의 키에 값을 쓰는 스레드 10 개를 시작하면 (Thread 1은 array[0] 에 쓰기) 스레드 2는 array[1] 에 씁니다. 등) 스레드가 배열을 캐시하려고 시도합니까 아니면 모든 변경 사항이 주 메모리에 적용됩니까?


  • 답변 # 1

    스레드는 비 휘발성 값을 캐시 할 수 있습니다.

    특히, 스레드 코드는 boolean 코드에 인라인 될 수 있습니다  스레드가 변경되지 않는 값. 스레드가 다시 컴파일 될 때까지 변경 사항을 감지하지 못할 수 있습니다.

    이 경우 배열 참조와 배열의 값이 모두 캐시되지만 일정 시간이 지나면 새 값이 표시 될 가능성이 높습니다.

    final 의 사용  실질적인 차이가 없습니다. 한 가지 이유는 반성을 통해 final 를 변경할 수 있기 때문입니다.  필드.

    이와 같은 스레드 안전 배열을 사용하는 더 확실한 방법은 AtomicIntegerArray 를 사용하는 것입니다.  Java 5.0에 추가됨

    final AtomicIntegerArray array = new AtomicIntegerArray(10);
    public void increment(int n) {
        array.incrementAndGet(n);
    }
    
    

  • 답변 # 2

    final은 개별 배열 요소에 대한 가시성 의미가 없으며, 휘발성이라도 요소가 아닌 참조 돌연변이 자체에서 순서 이전에 발생하는 것을 보장합니다. 이를 위해서는 대신 CopyOnWriteArrayList를 동기화하거나 사용해야합니다.

  • 답변 # 3

    업데이트

    와이즈 비즈  수정자는 모든 final 를 확인합니다 -s는해당 참조의 초기화 된 값을 볼 수 있습니다. 이것은 중요하다 : Thread  키워드는 배열 만 나타내지 만 해당 배열 내에 저장된 값은 아닙니다.

    원래 답변

    무슨 일이 일어날 지알지않습니다. JVM이 값을 캐시하거나 캐시하지 않을 수 있습니다. 나는 이것에 의존하지 않는 것이 좋습니다.

    시인성을 원한다고 생각합니다. 일반적으로 final 를 사용하여 가시성을 강제 할 수 있습니다.  키워드 또는 volatile . 이 경우 정수인 경우 배열이 있습니다.

    synchronization 의 배열 -s

    AtomicInteger 배열로 바꿀 수 있습니다  -s :

    AtomicInteger
    
    

    이 경우에는 값을 약간 다르게 조작해야합니다.

    private final AtomicInteger[] array = new AtomicInteger[10];
    
    
    동시 목록

    또 다른 접근법은 array[0] = new AtomicInteger(0); array[0].incrementAndGet(); 와 같은 동시 목록을 사용하는 것입니다.  또는 CopyOnWriteArrayList 를 사용하십시오  래퍼 방법 :

    Collections.synchronizedList()
    
    
    어느 쪽이든 // option 1 private final List<Integer> list = Collections.synchronizedList(new ArrayList<>()); // option 2 private final List<Integer> list = new CopyOnWriteArrayList<>(); 의 접근 자와는 약간 다른 접근자가 있습니다. . List 초기화는 가장 까다로운 부분입니다 :

    array
    
    
    동시지도

    지도를 사용할 수도 있으므로 문제가있는 초기화를 건너 뛸 수 있습니다 :

    // this prevents all kinf of OutOfBoundsException-s
    for (int i = 0; i < 10; i++) {
        list.add(0);
    }
    // and now you can use it
    list.set(0, list.get(0) + 1);
    
    
    private final ConcurrentMap<Integer, Integer> map = new ConcurrentHashMap<>(); // ... map.putIfAbsent(0, 0); map.put(0, map.get(0) + 1);

  • 이전 mongodb와 PHP에서 2 개의 컬렉션 데이터를 정렬 및 페이지 매김과 결합
  • 다음 c++17 - C ++ 이름 확인 문제