2012-11-21 4 views
2

저는 현재 Java로 멀티 스레딩에 대해 배우고 있으며 흥미로운 문제가 있습니다. 일부 CSV 파일을 읽는 "loader"클래스가 있습니다.다른 스레드가 실행되는 동안 작업 수행

public class LoaderThread implements Runnable{ 

@Override 
public void run(){ 
//do some fancy stuff 
} 
} 

데이터가로드되는 동안 표시 할 SplashScreen이 있습니다. 사용자가 버튼을 클릭 할 때

import javax.swing.JLabel; 
import javax.swing.JWindow; 
import javax.swing.SwingConstants; 

public class SplashScreen extends JWindow{ 

JWindow jwin = new JWindow(); 

public SplashScreen(){ 

jwin.getContentPane().add(new JLabel("Loading...please wait!",SwingConstants.CENTER)); 
jwin.setBounds(200, 200, 200, 100); 

jwin.setLocationRelativeTo(null); 

jwin.setVisible(true); 

try { 
    Thread.sleep(3000); 
} catch (InterruptedException e) { 
    Thread.currentThread().interrupt(); 
} 

jwin.setVisible(false); 
jwin.dispose(); 

} 
} 

코드는 내 주요 클래스에서 실행 :이 설정은 작동하지만 부하가 이상 3 초를 소요 할 때 메시지는 "깜박"입니다

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {           


    final Thread t = new Thread() { 

      @Override 
      public void run() { 

       LoaderThread myRunnable = new LoaderThread(); 
       Thread myThread = new Thread(myRunnable); 
       myThread.setDaemon(true); 
       myThread.start(); 
       while(myThread.isAlive()==true) 
       { 
        SplashScreen ss = new SplashScreen(); 
       } 


      } 
     }; 
     t.start(); // call back run() 
     Thread.currentThread().interrupt();   

}     

로드 프로세스가 더 짧을 수도 있지만 적어도 3 초 동안 표시됩니다.

로딩 스레드가 실행되는 동안 메시지를 표시 할 수 있는지 궁금합니다. 더 이상 짧지 않습니다.

미리 감사드립니다.

답변

5

이것은 관찰자 패턴이 잘 작동하는 완벽한 예입니다. Swing에서이 작업을 쉽게 수행하는 한 가지 방법은 백그라운드 스레드에 SwingWorker를 사용하는 것입니다. SwingWorker를 실행할 때 스플래시 화면을 표시하십시오. SwingWorker를 실행하기 전에 PropertyChangeListener를 추가하고 SwingWorker.StateValue.DONE을 반환하면 스플래시 화면을 제거하십시오.

또한 스윙 이벤트 스레드에서 Thread.sleep(...)을 호출하지 마세요. 재난에 대한 보장이므로 그렇게하십시오. 귀하의 코멘트에 대해서는

편집 한
-

는 "또한 ... 스윙 이벤트 스레드에서 Thread.sleep를 호출하지 마십시오"무엇을 의미합니까? "Swing 이벤트 스레드에서 Thread.sleep을 호출하지 마십시오 ..."라는 의미는 무엇입니까?

D 배출 그렇지 않으면, 스윙 이벤트 스레드에서 호출 동부 서머 타임 또는 E로 알려진되고 ispatch T hread :

try { 
    Thread.sleep(3000); 
} catch (InterruptedException e) { 
    Thread.currentThread().interrupt(); 
} 

이 수면에 전체 응용 프로그램을 넣어 것입니다 완전히 반응이 없으므로 EDT에 Thread.sleep(...) 번으로 전화하지 않는 것이 좋습니다.

편집 2
예제 코드 : 당신은 모니터 http://en.wikipedia.org/wiki/Monitor_(synchronization)

당신이 작업을 완료하고 대기되지 않은 경우 스레드가 종료되도록 할 수 있습니다 그 방법을 사용할 수

import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 

import javax.swing.*; 

public class SwingWorkerEg extends JPanel { 
    private static final int PREF_W = 300; 
    private static final int PREF_H = 200; 

    public SwingWorkerEg() { 
     add(new JButton(new ButtonAction("Press Me"))); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(PREF_W, PREF_H); 
    } 

    private static void createAndShowGui() { 
     JFrame frame = new JFrame("SwingWorkerEg"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(new SwingWorkerEg()); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGui(); 
     } 
     }); 
    } 
} 

class ButtonAction extends AbstractAction { 
    public ButtonAction(String title) { 
     super(title); 
    } 

    @Override 
    public void actionPerformed(ActionEvent actEvt) { 
     final JButton source = (JButton)actEvt.getSource(); 
     source.setEnabled(false); 
     MySwingWorker mySw = new MySwingWorker(); 
     final MySplashScreen mySplash = new MySplashScreen(); 
     mySplash.setVisible(true); 

     mySw.addPropertyChangeListener(new PropertyChangeListener() { 

     @Override 
     public void propertyChange(PropertyChangeEvent pcEvt) { 
      if (SwingWorker.StateValue.DONE == pcEvt.getNewValue()) { 
       mySplash.setVisible(false); 
       mySplash.dispose(); 
       source.setEnabled(true); 
      } 
     } 
     }); 
     mySw.execute(); 
    } 
} 

class MySwingWorker extends SwingWorker<Void, Void> { 
    private static final long SLEEP_TIME = 5 * 1000; 

    @Override 
    protected Void doInBackground() throws Exception { 
     Thread.sleep(SLEEP_TIME); // emulate long-running task 
     return null; 
    } 
} 

class MySplashScreen extends JWindow { 
    private static final String LABEL_TEXT = "Loading, ... please wait..."; 
    private static final int PREF_W = 500; 
    private static final int PREF_H = 300; 

    public MySplashScreen() { 
     add(new JLabel(LABEL_TEXT, SwingConstants.CENTER)); 
     pack(); 
     setLocationRelativeTo(null); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(PREF_W, PREF_H); 
    } 
} 
+0

감사합니다. SwingWorker를 살펴보십시오! "Swing 이벤트 스레드에서 Thread.sleep을 호출하지 마십시오 ..."라는 의미는 무엇입니까? – user1204121

+0

@ user1204121 : 1을 편집하고 2를 편집하십시오. –

+0

완벽하게 작동합니다. - 고맙습니다. – user1204121

5

루프에서 새 인스턴스를 만들고 있으므로 깜박입니다. 오히려 하나의 인스턴스를 생성하고 그것을 보이도록 만들고, 다른 스레드가 실행을 끝내면 그것을 버리십시오.

+0

이렇게 구현하면 효과적입니다. 공공 무효 실행() { SplashScreen splashScreen = new SplashScreen(); LoaderThread myRunnable = new LoaderThread(); 스레드 myThread = 새 스레드 (myRunnable); myThread.setDaemon (true); myThread.start(); if (myThread.isAlive() == false) { splashScreen.dispose(); } } – user1204121

1

임의의 수면.

은 기본적으로이 작업을 수행 할 (확장 할 필요) :

public class Monitor { 
    private boolean task = false; 

    public void synchronized waitForTask(){ 
    while(!task){ 
     wait(); 
    } 
    } 

    public void synchronized taskIsDone(){ 
    task = true; 
    notifyAll(); 
    } 
} 

두 개체는이 모니터에 대한 참조가 필요합니다. 뷰는 waitForTask를 호출해야하며 태스크는 taskIsDone을 ​​호출합니다.

관련 문제