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


192

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


16
왜 닫혀 있습니까? 이것은 Java에서 동시성을 구하는 다른 프로그래머와 다른 Java 개발자가 가장 많이 관찰하는 동시성 결함 클래스에 대한 아이디어를 얻는 데 유용합니다.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ 2013 년

@Longpoke 폐쇄 메시지는 폐쇄 이유를 설명합니다. 이것은 특정한 "올바른"답변을 가진 질문이 아니며, 여론 조사 / 목록 질문에 더 가깝습니다. 스택 오버플로는 이러한 종류의 질문을 호스팅하지 않습니다. 당신이 그 정책에 동의하지 않을 경우, 당신은 그것을 토론 할 수있다 메타 .
Andrzej Doyle

7
이 기사가 하루에 100 회 이상 조회되면 커뮤니티가 동의하지 않는 것 같습니다. 동시성 문제 contemplateltd.com/threadsafe 를 해결하기 위해 특별히 설계된 정적 분석 도구 개발에 참여하면서 매우 유용하다는 것을 알았습니다 . 일반적으로 발생하는 동시성 문제가있는 은행은 ThreadSafe를 테스트하고 개선하는 데 큰 도움이되었습니다.
Craig Manson

Java Concurrency의 코드 검토 체크리스트는 이 질문에 대한 답변에 언급 된 대부분의 함정을 일상적인 코드 검토에 편리한 형식으로 요약합니다.
leventov

답변:


125

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

class MyThread extends Thread {
  private boolean stop = false;

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

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

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


9
이에 대한 좋은 해결책은 중지 인스턴스 변수를 AtomicBoolean으로 만드는 것입니다. JMM 문제로부터 보호하면서 비 휘발성의 모든 문제를 해결합니다.
커크 와일리

39
'몇 분 동안'보다 더 나쁘다. 메모리 모델에서 JVM은 while (! stop)을 while (true)으로 최적화 한 다음 호스를 사용하게됩니다. 이것은 루프의 x 반복 후에 JVM이 다시 컴파일 될 때만 서버 모드에서만 일부 VM에서만 발생할 수 있습니다.
Cowan

2
휘발성 부울에 대해 AtomicBoolean을 사용하려는 이유는 무엇입니까? 버전 1.4 이상을 개발 중이므로 휘발성 선언으로 인한 함정이 있습니까?

2
Nick, 원자 CAS가 휘발성보다 훨씬 빠르기 때문이라고 생각합니다. 1.4를 위해 개발중인 유일한 안전한 옵션 IMHO는 1.4에서 휘발성으로 동기화 된 것을 사용하는 것이 Java 5에서와 같이 강력한 메모리 장벽을 보장하지 않습니다.
Kutzi

5
@Thomas : Java 메모리 모델 때문입니다. 자세히 알고 싶다면 그것에 대해 읽어야합니다 (Brian Goetz의 Java Concurrency는 실제로 잘 설명합니다). 간단히 말해, 메모리 동기화 키워드 / 구문 (휘발성, 동기화, AtomicXyz와 같이 스레드가 완료된 경우 등)을 사용하지 않는 한 하나의 스레드는 다른 스레드가 수행 한 모든 필드의 변경 사항을
보더라도

179

# 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서로 완전히 분리되어 선언되었지만 동일한 인스턴스로 나타납니다 . 결과는 분명히 나쁩니다.


63
이것이 내가 private static final Object를 선호하는 이유 중 하나입니다. LOCK = new Object ();
Andrzej Doyle

17
나는 그것을 좋아한다-오, 이것은 불쾌하다 :)
Thorbjørn Ravn Andersen

7
즉 자바 퍼즐 러 (Puzzler) 2.에 대한 좋은 하나입니다
도브 Wasserman

12
실제로 ... 실제로 컴파일러가 문자열에서 동기화를 거부하는 것을 원합니다. String interning을 고려할 때 이것이 "good thing (tm)"이되는 경우는 없습니다.
Jared

3
@Jared : "문자열이 끼워 질 때까지"의미가 없습니다. 현은 마술처럼 "인간"되지 않습니다. 지정된 String의 정식 인스턴스가없는 경우 String.intern ()은 다른 객체를 반환합니다. 또한 모든 리터럴 문자열과 문자열 값 상수 표현식이 인터 닝됩니다. 항상. JLS의 String.intern () 및 §3.10.5에 대한 문서를 참조하십시오.
Laurence Gonsalves

65

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

synchronized(foo) {
  foo = ...
}

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


19
이것에 대한 IDEA 검사는 "유용한 의미론을 갖지 않을 가능성이없는 최종 필드에서의 동기화"입니다. 아주 좋아요
Jen S.

8
하 .. 이제 고문 된 설명입니다. "유용한 의미론을 갖지 않을 것"은 "대부분 깨진 것"으로 더 잘 설명 될 수 있습니다. :)
Alex Miller

나는 그것이 ReadWriteLock에 이것을 가진 것이 Bitter Java라고 생각합니다. 다행스럽게도 이제 java.util.concurrency.locks가 있으며 Doug는 더 많은 공을 들고 있습니다.
Tom Hawtin-tackline

나는 또한이 문제를 자주 보았다. 그 문제에 대해서는 최종 객체에서만 동기화하십시오. FindBugs et al. 도와주세요
gimpf 2016 년

과제 중 문제 일 뿐입니 까? (아래지도와 함께 @Alex Miller의 예를 참조하십시오) 그지도 예에서도 같은 문제가 있습니까?
Alex Beardsley

50

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


이 버전의 버그가 포함 된 오픈 소스 프로젝트를 알고 있습니까? 실제 소프트웨어에서이 버그의 구체적인 예를 찾고 있습니다.
reprogrammer

48

에 의해 반환 된 객체 , 특히 반복 또는 여러 작업 중에 올바르게 동기화 되지 않음 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");

6
또는 ConcurrentHashMap 및 putIfAbsent를 사용하는 것이 좋습니다.
Tom Hawtin-tackline

47

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

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 메모리 모델의 복잡성에 익숙하지 않은 사람들은 이것을 항상 혼란스럽게 한다 .


7
열거 형 싱글 톤 패턴은 이러한 모든 문제를 해결합니다 (이에 대한 Josh Bloch의 의견 참조). Java 프로그래머에게는 그 존재에 대한 지식이 더 널리 퍼져 있어야합니다.
Robin

싱글 톤의 게으른 초기화가 실제로 적절한 단일 사례를 아직 실행하지 못했습니다. 그리고 그렇다면 동기화 된 메소드를 선언하십시오.
Dov Wasserman

3
이것이 Singleton 클래스의 지연 초기화에 사용하는 것입니다. 또한 java에서 암시 적으로 보장하므로 동기화가 필요하지 않습니다. 클래스 Foo {정적 클래스 홀더 {정적 Foo foo = 새 Foo (); } 정적 Foo getInstance () {return Holder.foo; }}
Irfan Zulfiqar

내가 기억하는 것에서 Pul의 방법이라고 불리는 Irfan
Chris R

@Robin, 정적 이니셜 라이저를 사용하는 것이 더 간단하지 않습니까? 그것들은 항상 동기화되어 실행되도록 보장됩니다.
matt b

37

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

java.util.ConcurrentModificationException

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

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

아니, 그건 내가 찾고있는 전부 야. 감사!
Alex Miller

30

동기화 된 컬렉션은 실제보다 더 많은 보호 기능을 제공한다고 생각하기 쉬울 수 있으며 통화 간 잠금을 유지하는 것을 잊어 버립니다. 나는이 실수를 몇 번 보았습니다.

 List<String> l = Collections.synchronizedList(new ArrayList<String>());
 String[] s = l.toArray(new String[l.size()]);

예를 들어, 위의 두 번째 줄에서 toArray()and size()메소드는 모두 자체적으로 스레드로부터 안전하지만 size()는와 별도로 평가되며 toArray()List의 잠금은이 두 호출 사이에 유지되지 않습니다.

목록에서 항목을 동시에 제거하는 다른 스레드와 함께이 코드를 실행하면 조만간 목록의 String[]모든 요소를 ​​보유하는 데 필요한 것보다 크고 새로 꼬리 값이 있는 새 리턴이 발생합니다. List에 대한 두 개의 메소드 호출이 단일 코드 행에서 발생하기 때문에 이것은 다소 원자 적 인 작업이지만 그렇지는 않다고 생각하기 쉽습니다.


5
좋은 예입니다. 필자는 이것을 "원자 연산의 구성이 원자가 아니다"라고보다 일반적으로 설명했다. (또 다른 간단한 예는 휘발성 필드 ++ 참조)
Alex Miller

29

우리가 일하는 곳에서 가장 일반적인 버그는 프로그래머가 EDT에서 서버 호출과 같은 긴 작업을 수행하고 몇 초 동안 GUI를 잠그고 앱이 응답하지 않는 것입니다.


그 답변 중 하나에 대해 한 가지 이상의 포인트를 줄 수 있기를 바랍니다
Epaga

2
EDT = 이벤트 발송 스레드
mjj1409

28

루프에서 wait () (또는 Condition.await ())를 잊어 대기 조건이 실제로 true인지 확인합니다. 이것이 없으면 가짜 대기 () 웨이크 업으로 인한 버그가 발생합니다. 정식 사용법은 다음과 같아야합니다.

 synchronized (obj) {
     while (<condition does not hold>) {
         obj.wait();
     }
     // do stuff based on condition being true
 }

26

또 다른 일반적인 버그는 잘못된 예외 처리입니다. 백그라운드 스레드가 예외를 처리 할 때 올바르게 처리하지 않으면 스택 추적이 전혀 표시되지 않을 수 있습니다. 또는 예외 처리에 실패하여 백그라운드 작업 실행이 중지되고 다시 시작되지 않을 수 있습니다.


그렇습니다. 이제 핸들러로 처리 할 수있는 유용한 도구가 있습니다.
Alex Miller

3
더 자세히 설명하는 기사 나 참조에 대한 링크를 게시 할 수 있습니까?
Abhijeet Kashnia

22

나는 비를 동기화 몰랐어요 브라이언 게츠 I와 클래스를했다 때까지 getter동기화를 통해 돌연변이 private 필드의 setter되어 결코 업데이트 된 값을 반환 보장하지 않습니다. 변수가 읽기 및 쓰기 에서 동기화 된 블록으로 보호되는 경우에만 변수 의 최신 값을 보장 할 수 있습니다.

public class SomeClass{
    private Integer thing = 1;

    public synchronized void setThing(Integer thing)
        this.thing = thing;
    }

    /**
     * This may return 1 forever and ever no matter what is set
     * because the read is not synched
     */
    public Integer getThing(){
        return thing;  
    }
}

5
이후의 JVM (1.5 이상)에서는 휘발성을 사용하면 문제가 해결됩니다.
James Schek

2
반드시 그런 것은 아닙니다. volatile은 최신 값을 제공하므로 1의 반환을 영원히 방지하지만 잠금은 제공하지 않습니다. 가깝지만 같지는 않습니다.
John Russell

1
@JohnRussell 나는 휘발성이 이전의 관계를 보장한다고 생각했습니다. "잠금"아닌가요? "휘발성 변수에 쓰기 (§8.3.1.4) v는 모든 스레드에 의해 v의 모든 후속 읽기와 동기화됩니다 (여기서는 동기화 순서에 따라 정의 됨)."
Shawn

15

단일 스레드 코드를 작성하고 있지만 가변 정적 (싱글 톤 포함)을 사용한다고 생각합니다. 분명히 스레드간에 공유됩니다. 이것은 놀랍게도 자주 발생합니다.


3
네 확실합니다! 가변성 스태틱은 스레드 감금을 끊습니다. 놀랍게도 JCiP 또는 CPJ에서이 함정에 대해 아무것도 찾지 못했습니다.
Julien Chastang

나는 이것이 동시 프로그래밍을하는 사람들에게 분명하기를 바랍니다. 스레드 상태를 확인하기 위해서는 전역 상태가 가장 먼저 있어야합니다.
gtrak

1
@Gary Thing은 동시 프로그래밍을하고 있다고 생각하지 않습니다.
Tom Hawtin-tackline

15

동기화 된 블록 내에서 임의의 메소드 호출을 수행해서는 안됩니다.

Dave Ray는 첫 번째 답변에서 이것을 만졌으며 실제로 동기화 된 메소드 내에서 리스너의 메소드를 호출하는 것과 관련하여 교착 상태가 발생했습니다. 더 일반적인 교훈은 동기화 된 블록 내에서 메소드 호출을 "실제로"해서는 안된다는 것입니다. 호출이 오래 실행되거나 교착 상태가 발생하는지 여부는 알 수 없습니다.

이 경우 일반적으로 해결 방법은 중요한 개인 코드 섹션을 보호하기 위해 동기화 된 블록의 범위를 줄이는 것 입니다.

또한 동기화 된 블록 외부의 리스너 컬렉션에 액세스하고 있었으므로 쓰기시 복사 컬렉션으로 변경했습니다. 또는 단순히 컬렉션의 방어 사본을 만들 수도 있습니다. 요점은 일반적으로 알 수없는 객체의 컬렉션에 안전하게 액세스 할 수있는 대안이 있다는 것입니다.


13

가장 최근에 발생한 동시성 관련 버그는 해당 생성자에서 ExecutorService를 생성 한 객체 였지만 객체가 더 이상 참조되지 않았을 때 ExecutorService를 종료하지 않았습니다. 따라서 몇 주에 걸쳐 수천 개의 스레드가 누출되어 결국 시스템이 중단되었습니다. (기술적으로 충돌하지는 않았지만 계속 실행되는 동안 제대로 작동하지 않았습니다.)

기술적으로, 이것이 동시성 문제는 아니지만 java.util.concurrency 라이브러리 사용과 관련된 문제라고 생각합니다.


11

불균형 동기화, 특히지도에 대한 동기화는 상당히 일반적인 문제인 것 같습니다. 많은 사람들은 동기화를 통해 Map (ConcurrentMap이 아니라 HashMap이라고 함)에 동기화하고 가져 오기를 동기화하지 않는 것으로 충분하다고 생각합니다. 그러나 이것은 다시 해시하는 동안 무한 루프로 이어질 수 있습니다.

그러나 읽기 및 쓰기와 공유 상태가있는 모든 위치에서 동일한 문제 (부분 동기화)가 발생할 수 있습니다.


11

각 요청에 의해 설정되는 변경 가능한 필드가있을 때 서블릿에 동시성 문제가 발생했습니다. 그러나 모든 요청에 ​​대해 하나의 서블릿 인스턴스 만 있으므로 단일 사용자 환경에서 완벽하게 작동했지만 둘 이상의 사용자가 서블릿을 요청하면 예기치 않은 결과가 발생했습니다.

public class MyServlet implements Servlet{
    private Object something;

    public void service(ServletRequest request, ServletResponse response)
        throws ServletException, IOException{
        this.something = request.getAttribute("something");
        doSomething();
    }

    private void doSomething(){
        this.something ...
    }
}

10

정확히 버그는 아니지만 최악의 죄는 다른 사람들이 사용할 라이브러리를 제공하지만 어떤 클래스 / 메소드가 스레드로부터 안전하고 어떤 클래스 / 메소드가 단일 스레드에서만 호출되어야하는지 명시하지 않는 것입니다.

더 많은 사람들이 Goetz의 책에 설명 된 동시성 주석 (예 : @ThreadSafe, @GuardedBy 등)을 사용해야합니다.


9

내 가장 큰 문제는 항상 교착 상태였습니다. 특히 자물쇠를 들고 발사 된 청취자 때문에 발생합니다. 이 경우 두 스레드 사이에서 반전 잠금을 얻는 것이 정말 쉽습니다. 필자의 경우 하나의 스레드에서 실행되는 시뮬레이션과 UI 스레드에서 실행되는 시뮬레이션의 시각화 사이에 있습니다.

편집 : 답변을 분리하기 위해 두 번째 부분으로 이동했습니다.


마지막 답변을 별도의 답변으로 나눌 수 있습니까? 게시물 당 1을 유지합시다. 이것들은 정말 좋은 두 가지입니다.
Alex Miller

9

클래스 생성자 내에서 스레드를 시작하는 것은 문제가 있습니다. 클래스가 확장되면 서브 클래스 생성자 가 실행 되기 전에 스레드를 시작할 수 있습니다 .


8

공유 데이터 구조의 가변 클래스

Thread1:
    Person p = new Person("John");
    sharedMap.put("Key", p);
    assert(p.getName().equals("John");  // sometimes passes, sometimes fails

Thread2:
    Person p = sharedMap.get("Key");
    p.setName("Alfonso");

이런 일이 발생하면 코드는이 간단한 예제보다 훨씬 복잡합니다. 버그 복제, 찾기 및 수정이 어렵습니다. 아마도 특정 클래스를 불변의 것으로 표시하고 특정 데이터 구조를 불변의 객체 만 보유하는 것으로 표시하면 피할 수 있습니다.


8

문자열 리터럴로 정의 된 문자열 리터럴 또는 상수에서 동기화하는 것은 (잠재적으로) 문자열 리터럴이 인터 닝되어 동일한 문자열 리터럴을 사용하여 JVM의 다른 사용자가 공유하므로 문제가 될 수 있습니다. 응용 프로그램 서버 및 기타 "컨테이너"시나리오에서이 문제가 발생했음을 알고 있습니다.

예:

private static final String SOMETHING = "foo";

synchronized(SOMETHING) {
   //
}

이 경우 문자열 "foo"를 사용하여 잠그는 사람은 모두 동일한 잠금을 공유합니다.


잠재적으로 잠겨 있습니다. 문제는 WHEN 문자열이 삽입 된 의미가 정의되지 않았거나 IMNSHO, 정의되지 않았다는 것입니다. "foo"의 컴파일러 시간 상수가 인터 워킹되고, 네트워크 인터페이스에서 들어오는 "foo"는 인터 워킹 할 경우에만 인터 턴됩니다.
커크 와일리

그렇기 때문에 리터럴 문자열 상수를 구체적으로 사용했습니다.
Alex Miller

8

나는 미래에 Java의 주요 문제는 생성자에 대한 가시성이 보장되지 않을 것이라고 믿습니다. 예를 들어 다음과 같은 클래스를 만드는 경우

class MyClass {
    public int a = 1;
}

그런 다음 다른 스레드에서 MyClass의 속성 a 를 읽습니다. MyClass.a는 JavaVM의 구현 및 분위기에 따라 0 또는 1이 될 수 있습니다. 오늘날 'a'가 1이 될 가능성은 매우 높습니다. 그러나 향후 NUMA 머신에서는 다를 수 있습니다. 많은 사람들이이를 인식하지 못하고 초기화 단계에서 멀티 스레딩에 신경 쓸 필요가 없다고 생각합니다.


나는 이것이 약간 놀랍다는 것을 알지만, 나는 당신이 똑똑한 친구 Tim이라는 것을 알고 있으므로 참조하지 않고 가져갈 것입니다. :) 그러나 a가 최종적이라면 이것이 걱정되지 않을 것입니다. 맞습니까? 그러면 건설 중에 최종 동결 의미론에 구속됩니까?
Alex Miller

나는 여전히 JMM에서 나를 놀라게하는 것을 발견하므로 나를 믿지 않을 것이지만 이것에 대해 확신합니다. cs.umd.edu/~pugh/java/memoryModel/… 도 참조하십시오 . 필드가 최종적인 경우 문제가되지 않으며 초기화 단계 후에 표시됩니다.
Tim Jansen

2
새로 생성 된 인스턴스의 참조가 생성자가 반환 / 완료되기 전에 이미 사용중인 경우에만 문제가됩니다. 예를 들어, 퍼블릭 풀에서 생성하는 동안 클래스 자체가 등록되고 다른 스레드가 액세스하기 시작합니다.
ReneS

3
MyClass.a는 정적 액세스를 나타내며 'a'는 MyClass의 정적 멤버가 아닙니다. 그 외에는 'ReneS'상태이므로 생성자에서 외부 맵에 'this'를 추가하는 것과 같이 완료되지 않은 객체에 대한 참조가 유출되는 경우에만 문제가됩니다.
Markus Jevring

7

내가 가장 자주 저지르는 실수는 객체에서 notify () 또는 wait ()를 호출하기 전에 동기화하는 것을 잊어 버리는 것입니다.


8
대부분의 동시성 문제와 달리 쉽게 찾을 수 없습니까? 적어도 여기에서 IllegalMonitorStateException이 발생합니다.
무법자 프로그래머

고맙게도 찾기는 매우 쉽지만 ...하지만 여전히 내 시간을 낭비하는 바보 같은 실수입니다 :)
Dave Ray

7

로컬 "new Object ()"를 뮤텍스로 사용.

synchronized (new Object())
{
    System.out.println("sdfs");
}

이것은 쓸모가 없습니다.


2
이것은 아마도 쓸모가 없지만 동기화 작업은 흥미로운 일을합니다. 매번 새로운 객체를 생성하는 것은 완전한 낭비입니다.
TREE

4
쓸모가 없습니다. 잠금 장치가없는 메모리 배리어입니다.
David Roussel

1
@ 데이비드 : 유일한 문제는 - JVM은 전혀 같은 잠금 장치를 제거하여 최적화 할 수
yetanothercoder

@insighter 나는 당신의 의견을 공유 볼 ibm.com/developerworks/java/library/j-jtp10185/index.html 나는 그것을 할 수있는 어리석은 일이 있음을 동의 당신이 당신의 memoery 장벽 동기화 할 때 알고하지 않는 한, I 그게 아무것도하지 않는 것이라고 지적했습니다.
David Roussel 2016 년

7

또 다른 일반적인 '동시성'문제는 전혀 필요하지 않은 경우 동기화 된 코드를 사용하는 것입니다. 예를 들어 여전히 프로그래머가 StringBuffer또는 java.util.Vector메서드를 로컬 메서드를 사용하여 볼 수 있습니다.


1
JVM이 전역 메모리에 대해 데이터를 동기화하도록 지시하므로 다중 CPU에서 잘못 실행될 수 있으므로 동기화 블록을 동시에 사용하는 사람은 아무도 없으므로 문제는 아니지만 불필요합니다.
ReneS

6

잠금으로 보호되어 있지만 일반적으로 연속적으로 액세스되는 여러 개체. 우리는 서로 다른 코드로 다른 순서로 잠금을 획득하여 교착 상태가 발생하는 몇 가지 사례를 겪었습니다.


5

this내부 클래스의 내부 클래스가 this외부 클래스의 클래스가 아님을 인식 하지 못합니다 일반적으로 구현하는 익명의 내부 클래스에서 Runnable. 근본적인 문제는 동기화가 모든 것의 일부이기 때문에 Object정적 유형 검사가 사실상 없다는 것입니다. 나는 이것을 유즈넷에서 적어도 두 번 보았으며 Brian Goetz의 Java Concurrency in Practice에도 나타납니다.

BGGA 클로저는 클로저가 없기 때문에이 문제를 겪지 않습니다 this( this외부 클래스 참조). 비 this객체를 잠금으로 사용하면 이 문제와 다른 문제가 해결됩니다.


3

잠금을위한 정적 변수와 같은 전역 객체 사용.

경합으로 인해 성능이 매우 저하됩니다.


글쎄, 때로는, 때로는 그렇지 않습니다. 그렇게 쉬운 일이라면 ...
gimpf

스레딩이 주어진 문제에 대한 성능을 향상시키는 데 도움이된다고 가정하면 둘 이상의 스레드가 잠금으로 보호되는 코드에 액세스하자마자 항상 성능이 저하됩니다.
kohlerm

3

솔직히? 의 출현 이전에, java.util.concurrent내가 일상적으로 겪었던 가장 일반적인 문제는 "스레딩 스레 싱 (thread-thrashing)"이라고했습니다.


java.util.concurrent를 사용할 수 있으므로 더 많은 문제가 발생 했음을 의미 합니까?
Andrzej Doyle
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.