Java 컬렉션 인스턴스의 동기화 블록과 final

조회수 658회

코드:

public class MainClass {
  //###
  public static final List<Integer> lst = Collections.synchronizedList(new ArrayList<>());

  public static void main(String[] args) {
    for (int i = 0; i < 16; ++i) {
      lst.add(i);
    }
    System.out.println(lst);

    Runnable task = () -> {
      synchronized (lst) {
        ListIterator<Integer> itr = lst.listIterator();
        while (itr.hasNext()) {
          itr.set(itr.next() + 1);
        }
      }
    };

    ExecutorService exr = Executors.newFixedThreadPool(3);

    exr.submit(task);
    exr.submit(task);
    exr.submit(task);

    exr.shutdown();

    try {
      exr.awaitTermination(100, TimeUnit.SECONDS);
      System.out.println(lst);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

결과:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

세 개의 쓰레드를 가지는 쓰레드 풀을 생성하고, 세 쓰레드에 모두 동일한 작업(컬렉션 인스턴스의 각 원소 값을 1씩 증가)을 부여하는 코드입니다.

여기서 궁금한 게 있는데요...

  • List 참조변수 lst에 final을 선언하지 않으면, IntelliJ 에디터의 경우 synchronized (lst) {...} 부분에서 다음과 같은 경고를 띄웁니다. 이해가 잘 안 가는데 이게 무슨 뜻인가요?

Reports synchronized statements where the lock expression is a reference to a non-final field. Such statements are unlikely to have useful semantics, as different threads may be locking on different objects even when operating on the same object.

  • (•́ ✖ •̀)
    알 수 없는 사용자

1 답변

  • Synchronized block에서 동기화 대상이 되는 object가 final이 아니면 runtime에 object를 변경할 수 있다는 말과 같습니다.

    object가 중간에 변경되게 되면 각각의 thread에서 lock을 점유하는 대상이 달라지게 되기 때문에 Synchronized block 내부로 동시 접근이 가능해지게 됩니다.

    final 키워드를 붙여서 대상이 변경되는 것을 명시적으로 제한하지 않으면 개발자의 실수로 이런 문제가 발생할 수 있기 때문에 경고를 띄우는 것입니다.

    • (•́ ✖ •̀)
      알 수 없는 사용자
    • 답변 감사합니다. 그런데 런타임 시에 객체가 변경되는 일이 있을 수가 있나요? 알 수 없는 사용자 2019.1.15 15:13
    • non-final로 선언된 lst 에 다른 List object를 할당 할 수 있습니다. 알 수 없는 사용자 2019.1.15 15:20
    • 자바 가상 머신에 의해 실행 도중 임의로 객체가 바뀐다는 뜻인가요? 알 수 없는 사용자 2019.1.15 19:26
    • 음.. 그런 얘기가 아니라 MainClass의 멤버변수인 lst가 final 로 선언되지 않으면 최초 할당한 List객체 외에 다른 객체를 할당하도록 코딩하는 것이 문법적으로 허용된다는 얘기입니다. 반면에 final로 선언하여 read-only로 만들어준다면 최초 할당했던 List객체가 프로그램이 종료될 때 까지 불변하다는 것이 보장되기 때문에 권장하는 것입니다. 알 수 없는 사용자 2019.1.15 19:36
    • 아 그렇군요...감사합니다 알 수 없는 사용자 2019.1.16 01:56

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)