1

내가 읽고있어. Java에서 생각하고 저자는 기본 메서드가 스윙 메서드를 호출해서는 안된다고 강조했다.자바 스윙에서 스레드 안전 방식으로 gui 객체를 초기화하는 방법은 무엇입니까?

//: gui/SubmitSwingProgram.java 
import javax.swing.*; 
import java.util.concurrent.*; 

public class SubmitSwingProgram extends JFrame { 
    JLabel label; 
    public SubmitSwingProgram() { 
    super("Hello Swing"); 
    label = new JLabel("A Label"); 
    add(label); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setSize(300, 100); 
    setVisible(true); 
    } 
    static SubmitSwingProgram ssp; 
    public static void main(String[] args) throws Exception { 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { ssp = new SubmitSwingProgram(); } 
    }); 
    TimeUnit.SECONDS.sleep(1); 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
     ssp.label.setText("Hey! This is Different!"); 
     } 
    }); 
    } 
} ///:~ 

는 GUI 객체가 생성하고 스레드 안전하고 invokeLater 방법을 통해 초기화 : 그 연습의 예를 들어 그는 (자신의 웹 페이지에서 사용 가능) 다음 코드 조각을 제공합니다.

//: gui/Button2.java 
// Responding to button presses. 
import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 
import static net.mindview.util.SwingConsole.*; 

public class Button2 extends JFrame { 
    private JButton 
    b1 = new JButton("Button 1"), 
    b2 = new JButton("Button 2"); 
    private JTextField txt = new JTextField(10); 
    class ButtonListener implements ActionListener { 
    public void actionPerformed(ActionEvent e) { 
     String name = ((JButton)e.getSource()).getText(); 
     txt.setText(name); 
    } 
    } 
    private ButtonListener bl = new ButtonListener(); 
    public Button2() { 
    b1.addActionListener(bl); 
    b2.addActionListener(bl); 
    setLayout(new FlowLayout()); 
    add(b1); 
    add(b2); 
    add(txt); 
    } 
    public static void main(String[] args) { 
    run(new Button2(), 200, 150); 
    } 
} ///:~ 

SwingConsole은 다음과 같습니다 : 그러나 몇 페이지 나중에 저자는 다음과 같은 코드를 제공

//: net/mindview/util/SwingConsole.java 
// Tool for running Swing demos from the 
// console, both applets and JFrames. 
package net.mindview.util; 
import javax.swing.*; 

public class SwingConsole { 
    public static void 
    run(final JFrame f, final int width, final int height) { 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
     f.setTitle(f.getClass().getSimpleName()); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setSize(width, height); 
     f.setVisible(true); 
     } 
    }); 
    } 
} ///:~ 

JFrame의를 구현하는 객체 생성 및 주요 방법/메인 스레드 내에서 초기화 앞의 예에 따라서 반대 .

내 질문은 다음과 같습니다. (1) 두 번째 예가 잘못 되었습니까? 아니면 첫 번째 예가 과장입니까? (2) setVisible 호출 후에 만 ​​스윙 메서드를 호출하면 충분하며 기본 스레드 내에서 swing 메서드를 호출하는 것이 안전합니다.

+2

그는 프레임이 포장되거나 보이게 될 때까지 (다루기 때문에), 다루는 것이 안전하다고 주장 할 수 있습니다. 이 사고의 문제점은 요청 큐를 트리거 할 이벤트 큐가 무엇인지 모르는 것입니다. EDT – MadProgrammer

+0

컨텍스트 내에서 UI를 초기화하는 것이 더 안전합니다. 유용 할 수 있습니다. http://stackoverflow.com/questions/6393327/proper-way-to-start-java-swing-desktop-application – bancer

답변

5

두 번째 예는 잘못되었습니다. 스윙 구성 요소는 이벤트 발송 스레드에서 작성하여 사용해야합니다. https://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html을 참조하십시오. the javadoc에서

인용구 :

응용 프로그램의 main 메소드에 전화 또는 애플릿의 메소드는 이벤트 파견 스레드에서 호출되지 않습니다. 이와 같이 응용 프로그램 또는 애플릿을 생성하여 표시 할 때 이벤트 발송 스레드로 제어를 전송하려면주의해야합니다.

(강조 광산)

+0

예. 'run()'은 적절한 SwingUtilities 메소드를 호출하는 메소드에 대한 호출이지만, 실제 생성 ('new' 호출)은 주 스레드에서 호출됩니다. 안좋다! – markspace

+0

좋은 답변을 주셔서 감사합니다. 링크가 모든 것을 설명합니다. 그러나 나는 놀랐다. 나는 자바에 대한 생각이 언어를 배우기위한 더 좋은 소스 중 하나로 여겨진다 고 생각했다. –

-1

main() 메소드와 예 약간 잘못 될 수도있다. AFAIK 규칙은 주 스레드 만 스윙 업데이트/다시 그리기 등을 실행할 수 있으며 main() 메서드는 정의 은 주 스레드 인입니다. 다른 모든 스레드는 SwingUtilities.invokeLater (...)를 통해 항목을 예약해야합니다. 주 스레드의 경우에도 주 스레드에서 시간이 많이 걸리는 작업을 수행하고 주 스레드의 사용량이 적을 때마다 GUI가 새로 고침하므로 주 스레드의 경우에도 대기 시간이 향상 될 수 있습니다. 편집 : 입증 된 틀림

+3

나는 당신의 혼란스러운 용어를 생각한다. 일반적으로 메인 스레드는 프로그램을 시작하는 스레드 (메인 호출)로 간주된다. 스윙은 다른 스레드를 사용한다. 이벤트 스레드는 모든 UI 코드를 실행해야한다. – MadProgrammer