2011-07-27 3 views
4

invokeLater() Runnable에서 동시성을 보장 할 필요가 있는지 궁금합니다.Java Swing EDT 및 동시성

교착 상태가 발생하여 동시성을 유지하면서이를 극복해야합니다.

이 좋은 코드?

private String text; 

private void updateText() 
{ 
    SwingUtilities.invokeLater(new Runnable() 
    { 
     public void run() 
     { 
      synchronized(FrameImpl.this) 
      { 
       someLabel.setText(text); 
      } 
     } 
    }); 
} 

오히려 나쁜 예를 들어 미안하지만, 우리가 text가 다른 스레드에 의해 수정되고 있음을 가정해야 주입 할 수없는 예 수,과에 의존시겠습니까 올바른 값.

이 방법이 적합한가요? 아니면 알 수없는 컨텍스트에 동기 코드를 보내서 의도하지 않게 교착 상태 문제가 발생합니까?

감사합니다.

지금

답변

7

는 더 나은 솔루션이 같은 것입니다 :

public class Whatever { 
    private String text; 
    private final Object TEXT_LOCK = new Object(); 

    public void setText(final String newText) { 
     synchronized (TEXT_LOCK) { 
      text = newText; 
     } 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       someLabel.setText(newText); 
      } 
     }); 
    } 

    public String getText() { 
     synchronized (TEXT_LOCK) { 
      return text; 
     } 
    } 
} 

이 두 개의 스레드가 동시에 setText를 호출하려고하면 그들은 서로 소지품되지 않도록합니다. 첫 번째 스레드는 text 값을 설정하고 해당 값으로 UI 업데이트를 대기열에 추가합니다. 두 번째 스레드는 text 값을 설정하고 두 번째 UI 업데이트를 대기열에 추가합니다.

최종 결과는 UI가 결국 가장 최근 텍스트 값을 표시하지만 내부 text 변수는 즉시에 최신 값을 포함하게됩니다.

노트의 몇 : 별도의 락 객체 (즉 TEXT_LOCK)를 사용하여

  1. 당신이 Whatever 인스턴스 모니터 잠금 실수로 교착 상태의 원인이 다른 곳에 코드에 취약하지 않습니다 것을 의미합니다. 잠금 개체를 항상 엄격하게 제어하는 ​​것이 가장 좋습니다. 또한 동기화 된 블록의 크기를 최소화하는 것이 가장 좋습니다.
  2. 은 전체적으로 setText 메서드를 동기화합니다. 위와 같이 교착 상태에 취약해질 수 있다는 경고가 있습니다.
  3. text의 값을 읽는 경우에도 Strings을 변경할 수 없어도 동기화해야합니다. Java 메모리 모델에는 항상 이 여러 스레드에서 읽고 쓸 수있는 변수를 동기화해야한다는 미묘한 차이가 있습니다.

Brian Goetz의 Java Concurrency in Practice을 확인하면 동시성 (메모리 모델의 이상 함을 포함하여)의 까다로운 부분을 자세히 살펴볼 수 있습니다.

+0

이것은 작동하지 않습니다. 모달 JPanel에서. – YumYumYum

+0

@YumYumYum : 자세히 설명해 주시겠습니까? 작동하지 않는 것은 무엇입니까? –

-2

이 올바른 것은, 작업의 모든 출력이 InvokeLater(), 백그라운드 작업 (들)에서 업데이트 GUI에 대한 또 다른 예 ITO 포장해야하는 것은 here

private String text; 

private void updateText() { 

    synchronized (FrameImpl.this) { 
     SwingUtilities.invokeLater(new Runnable() { 

      public void run() { 
       someLabel.setText(text); 
      } 
     }); 
    } 
} 
+1

그래도 문제가 해결되지 않습니다. 'SwingUtilities.invokeLater'는 즉시 반환되며'run' 메서드는 동기화 된 범위 내에서 호출되지 않습니다. EDT에 Runnable을 추가하는 것만으로 동기화되며 필요하지 않습니다.이 구현으로'text'의 값은'invokeLater' 호출과'Runnable'의 실제 실행 사이에서 바뀔 수 있습니다. –

+0

나는 카메론에 동의한다. 나는 그것이 생산적 일을 아무것도하지 않을 것이라고 생각한다. 실행/제출 시간도 저와 관련이 없습니다. 단지'text' 값이 정확하고 교착 상태 문제가 없는지 확인하려고 노력하고 있습니다. 감사합니다. – Whired