2012-06-06 4 views
1

GUI (Swing)가있는 클라이언트 응용 프로그램을 작성하고 있습니다. 두 클래스 인 ClientClass와 MainFrame은 서로 다른 스레드를 실행 중이지만 서로 메서드를 호출해야합니다. ClientClass는 EventQueue 스레드 (displayGUI())의 응용 프로그램 수명주기 중 일부 지점에서 GUI (MainFrame)를 인스턴스화합니다. ClientClass는 recv()와 같이 MainFrame을 업데이트하는 클라이언트 클래스 thread에서 호출되는 많은 메소드를 포함합니다. 또한 MainFrame에는 ClientClass의 메서드를 호출하는 버튼을 누르는 것과 같은 이벤트에 의해 트리거되는 메서드가 있습니다. 이 예제에서 단추 누르기를 처리하는 애노 메서드가 EventQueue 스레드에 의해 호출되고 있다고 가정합니다.GUI 스레드간에 정보를 공유하는 방법은 무엇입니까?

저는 이런 종류의 응용 프로그램이 매우 일반적이며 다른 사람들의 통찰력을 좋아할 것이라고 확신합니다. 내가하는 일이 스레드로부터 안전하지 못하다는 느낌이 들었습니다. 그렇다면이 응용 프로그램의 현재 모델을 어떻게 수정하고 개선 할 수 있습니까?

예제 코드 :

MainFrame.java :

public MainFrame(ClientClass c) { 
    client = c; 

    // <Misc init code here> 

    btnSend = new JButton("Send"); 
    btnSend.addMouseListener(new MouseAdapter() { 
     @Override 
     public void mouseClicked(MouseEvent arg0) { 
      client.send("Hello!"); 
     } 
    }); 
    btnSend.setBounds(171, 120, 89, 23); 
    contentPane.add(btnSend); 
} 

public void updateElement() { 
    // Update of some element here, called from ClientClass 
} 

ClientClass.java :

private MainFrame mainFrame; 

public ClientClass() { 
} 

public void displayGUI() { 
    final ClientClass c = this; 

    EventQueue.invokeLater(new Runnable() { 
     public void run() { 
      try { 
       mainFrame = new MainFrame(c); 
       mainFrame.setVisible(true); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
} 

public void send(String msg) { 
    // Socket send operations here 
    // Currently called by the GUI's EventQueue thread? 
} 

public void recv() { 
    // Socket recv operations here 
    mainFrame.updateElement(); 
} 
+0

동시성에 대한 스윙 튜토리얼은 모든 질문에 답해야합니다. http://docs.oracle.com/javase/tutorial/uiswing/concurrency/ –

답변

2

당신은 SwingUtilities이 (UI 스레드에서) EDT에 코드를 호출하는 데 사용할 수 있습니다.

클릭하면 마우스가 UI 스레드에서 호출되므로 백그라운드에서 send을 호출해야합니다 (오래 걸리면 UI를 차단하지 않음). 당신이 (등 JLabel의 텍스트) GUI의 상태를 변경하는 경우 recv 방법에

당신은 UI 스레드에서 mainFrame.updateElement();를 호출해야합니다 - 당신은이 작업을 수행 :

SwingUtilities.invokeLater(new Runnable() {... // 

는 일반적으로 - 당신이이 GUI에 영향을 미칠 수 않는 것도 EDT에서해야하는 요소 (텍스트 변경, 무효화, 구성 요소 추가 등).

그리고 사용자 인터페이스를 차단할 수있는 모든 것은 백그라운드에서 수행해야합니다 - 새로운 Thread을 생성합니다.

당신이 어떤 이벤트를 차단하고 배경에 대기해야하는 경우 - 당신은 또한 SwingWorker 클래스에와 보라

- 당신이 모달 JDialog (다만 만일 당신이 finally 블록에 숨길 것을 기억)를 표시 할 수 있습니다 tutorial.

+0

응답 해 주셔서 감사합니다! 어쨌든 원래의 쓰레드 (ClientClass 쓰레드)를 보내 주려고합니까? – Ramsey

+1

GUI가 보낼 메시지를 추가 할 BlockingQueue를 사용할 수 있습니다. 주 스레드는이 대기열에서 메시지를 가져 와서 보냅니다. –

+1

@JB Nizet comment가 귀하의 질문에 대답합니다. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService도 확인해야합니다.html – Xeon

3

Xeon의 대답은 아마도이 특별한 경우에 당신에게 더 직접적으로 유용 할 것입니다. 그러나 일반적인 교장으로서 Singletons에서 읽을 수 있습니다.

하나의 싱글 톤 (설명하는 경우 Manager 또는 일부라고도 함)을 만들면 응용 프로그램과 관련된 '작업'을 수행하는 단일 클래스를 가질 수 있으며 GUI 스레드 (들)이 그 싱글 톤에 작업을 보냅니다.

관련 문제