[java] Java에서 가장 자주 발생하는 동시성 문제는 무엇입니까? [닫은]

이것은 Java의 일반적인 동시성 문제에 대한 일종의 설문 조사입니다. Swing의 전형적인 교착 상태 또는 경쟁 조건 또는 EDT 스레딩 버그가 그 예입니다. 가능한 광범위한 문제와 가장 일반적인 문제에 관심이 있습니다. 따라서 댓글 당 Java 동시성 버그에 대한 특정 답변을 하나 남겨두고 발생한 버그가 있으면 투표하십시오.



답변

내가 본 가장 일반적인 동시성 문제는 하나의 스레드로 작성된 필드가 다른 스레드로 표시 되지 않는다는 것을 인식 하지 못한다 는 것 입니다. 이것의 일반적인 응용 프로그램 :

class MyThread extends Thread {
  private boolean stop = false;

  public void run() {
    while(!stop) {
      doSomeWork();
    }
  }

  public void setStop() {
    this.stop = true;
  }
}

만큼 정지로하지 휘발성 이나 setStop하고 run있지 않습니다 동기화 이 작동하도록 보장 할 수 없습니다. 이 실수는 99.999 %에서 특히 끔찍합니다. 독자 스레드가 결국 변화를 볼 수 있기 때문에 실제로는 문제가되지 않습니다. 그러나 우리는 그가 얼마나 빨리 그것을 보았는지 모릅니다.


답변

# 1 가장 고통스러운 때 동시성 문제는 지금까지 발생한 두 개의 서로 다른 오픈 소스 라이브러리는 다음과 같이 뭔가를했다 :

private static final String LOCK = "LOCK";  // use matching strings 
                                            // in two different libraries

public doSomestuff() {
   synchronized(LOCK) {
       this.work();
   }
}

언뜻보기에 이것은 아주 간단한 동기화 예제처럼 보입니다. 하나; Strings는 Java 로 인턴 되기 때문에 리터럴 문자열 "LOCK"java.lang.String서로 완전히 분리되어 선언되었지만 동일한 인스턴스로 나타납니다 . 결과는 분명히 나쁩니다.


답변

하나의 고전적인 문제는 동기화하는 객체를 동기화하는 동안 변경하는 것입니다.

synchronized(foo) {
  foo = ...
}

그런 다음 다른 동시 스레드가 다른 개체에서 동기화되고이 블록은 예상 한 상호 배제를 제공하지 않습니다.


답변

일반적인 문제는 여러 스레드에서 Calendar 및 SimpleDateFormat과 같은 클래스를 동기화없이 사용하는 것입니다 (정적 변수로 캐싱). 이러한 클래스는 스레드로부터 안전하지 않으므로 다중 스레드 액세스는 궁극적으로 일관성이없는 상태에서 이상한 문제를 일으킬 수 있습니다.


답변

에 의해 반환 된 객체 , 특히 반복 또는 여러 작업 중에 올바르게 동기화 되지 않음 Collections.synchronizedXXX():

Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());

...

if(!map.containsKey("foo"))
    map.put("foo", "bar");

그건 잘못된 . 하나의 작업에도 불구하고 synchronized, 호출을 맵의 상태 contains와는 put다른 스레드에 의해 변경 될 수있다. 그것은해야한다:

synchronized(map) {
    if(!map.containsKey("foo"))
        map.put("foo", "bar");
}

또는 ConcurrentMap구현 :

map.putIfAbsent("foo", "bar");


답변

이중 확인 잠금. 전반적으로.

BEA에서 일할 때의 문제를 배우기 시작한 패러다임은 사람들이 다음과 같은 방식으로 싱글 톤을 검사한다는 것입니다.

public Class MySingleton {
  private static MySingleton s_instance;
  public static MySingleton getInstance() {
    if(s_instance == null) {
      synchronized(MySingleton.class) { s_instance = new MySingleton(); }
    }
    return s_instance;
  }
}

다른 스레드가 동기화 된 블록에 들어가서 s_instance가 더 이상 null이 아니기 때문에 이것은 작동하지 않습니다. 따라서 자연스런 변화는 다음과 같습니다.

  public static MySingleton getInstance() {
    if(s_instance == null) {
      synchronized(MySingleton.class) {
        if(s_instance == null) s_instance = new MySingleton();
      }
    }
    return s_instance;
  }

Java 메모리 모델이 지원하지 않기 때문에 작동하지 않습니다. s_instance를 휘발성으로 선언해야 작동하며 Java 5에서만 작동합니다.

Java 메모리 모델의 복잡성에 익숙하지 않은 사람들은 이것을 항상 혼란스럽게 한다 .


답변

아마도 정확히 당신이 요구하는 것은 아니지만, 내가 직면 한 가장 빈번한 동시성 관련 문제는 (아마도 일반적인 단일 스레드 코드에서 발생하기 때문에)

java.util.ConcurrentModificationException

다음과 같은 것들로 인해 발생합니다.

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (String string : list) { list.remove(string); }