2017-11-03 12 views
0

다시 시도해주세요! 다음 코드에서는 버튼을 눌러 타이머 스레드를 밀고 레이블에 타이핑하여 시작하려고합니다. 버튼을 누를 때마다 새 스레드가 시작되고 각 레이블에이를 표시해야합니다. 그러나 유감스럽게도 각 라벨마다 동일한 타이머가 기록됩니다. 우리가 올바르게 할 수 있도록 도와 줄 수 있습니까? 실수를 말할 수 있다면, 무슨 뜻입니까?멀티 스레드 타이머가 올바르게 작동하지 않습니다.

public class TimerThreads implements ActionListener{ 

    JFrame jFrame = new JFrame(); 
    JLabel[] labels; 
    int second = 0; 
    int minute = 0; 
    String s = ""; 
    String m = ""; 
    int l = 0; 


    public TimerThreads(){ 
     JLabel one = new JLabel(); 
     JLabel two = new JLabel(); 
     JLabel three = new JLabel(); 
     JLabel four = new JLabel(); 
     labels = new JLabel[]{one, two, three, four}; 

     jFrame.setLayout(new GridLayout(0, 2, 5, 5)); 
     jFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 

     JButton start = new JButton("Start"); 
     start.addActionListener(this); 

     JButton stop = new JButton("Stop"); 
     stop.addActionListener(this); 

     jFrame.add(start); 
     jFrame.add(stop); 
     jFrame.setVisible(true); 
     jFrame.pack(); 
    } 

    public static void main(String[] args) { 
     new TimerThreads(); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     String select = e.getActionCommand(); 
     switch(select){ 
      case "Start": 
       jFrame.add(labels[l]); 
       jFrame.revalidate(); 
       jFrame.repaint(); 
       TimerThread t = new TimerThread(labels[l]); 
       t.start(); 
       l++; 
       break; 
      case "Stop": 
       // 
       break; 
     } 
    } 

    class TimerThread extends Thread{ 
     JLabel jLabel; 

     public TimerThread(JLabel jLabel) { 
      this.jLabel = jLabel; 
     } 

     @Override 
     public void run() { 
      Timer timer = new Timer(); 
      timer.scheduleAtFixedRate(new TimerTask() { 
       @Override 
       public void run() { 
        second++; 
        if(String.valueOf(second).length() == 1){ 
         s = "0"; 
        } 
        else{ 
         s = ""; 
        } 
        if(second == 60){ 
         second = 0; 
         s = "0"; 
         minute++; 
        } 

        if(String.valueOf(minute).length() == 1){ 
         m = "0"; 
        } 
        jLabel.setText(m + String.valueOf(minute) + ":" + s + String.valueOf(second)); 
       } 
      },0, 1000); 
     } 
    } 
} 
+1

스윙 타이머 또는'javax.swing.Timer'를 사용해야 할 때'java.util.Timer'라는 잘못된 Timer를 사용하고 있습니다. 이것은 후자의 Timer가 Swing 이벤트 모델과 잘 작동하고 스레드 충돌을 방지하기 때문에 매우 중요합니다. 이것이 도움이되지 않으면 질문을 편집하고 스윙 타이머 시도를 보여주십시오. [스윙 타이머 튜토리얼] (http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html)을 확인하십시오. –

+0

다른 주요 문제점 (및 버그의 원인)은 s, m, second 및 minute를 포함하여 TimerThreads 클래스의 필드는 바깥 쪽 TimerThreads 클래스의 필드가 아니며 중첩 된 TimerTask 클래스의 필드 여야합니다. 이것이 모든 타이머가 같은 값을 공유하는 이유입니다. 다시 말해, Swing Timer를 사용해야하므로이 필드는 Swing Timer의 자체 ActionListener 필드 내에서 선언되어야합니다. –

+0

도움을 주신 것에 감사드립니다. 나는 반응하고 일했다. – PengeDroid

답변

2

버그의 원인은 여기에 있습니다 :

public class TimerThreads implements ActionListener { 

    JFrame jFrame = new JFrame(); 
    JLabel[] labels; 

    // ***** these fields below 
    int second = 0;  
    int minute = 0; 
    String s = ""; 
    String m = ""; 
    // ***** these fields above 

    int l = 0; 

네 개의 필드

클래스의 인스턴스 필드이며, 사용자가 만든 모든 TimerTask를 인스턴스에 의해 공유되는, 그래서 모두가 정확히 동일하게 표시됩니다 시각.

이 솔루션은 중첩 된 클래스에 이러한 필드 지역 있도록하는 것입니다 : 잘못된 타이머를 사용하고 있기 때문에


public class TimerThreads implements ActionListener { 

    JFrame jFrame = new JFrame(); 
    JLabel[] labels; 
    // int second = 0; 
    // int minute = 0; 
    // String s = ""; 
    // String m = ""; 
    int l = 0; 

    public TimerThreads() { 
     //..... 
    } 

    // .... 


    class TimerThread extends Thread { 
     JLabel jLabel; 

     public TimerThread(JLabel jLabel) { 
      this.jLabel = jLabel; 
     } 

     @Override 
     public void run() { 
      java.util.Timer timer = new java.util.Timer(); 
      timer.scheduleAtFixedRate(new TimerTask() { 

       // ***** add these fields here 
       int second = 0; 
       int minute = 0; 
       String s = ""; 
       String m = ""; 
가이 말을하는 데, 당신은 java.util의를 위험한 코드를 가지고 . Timer, Swing Timer 또는 javax.swing.Timer를 사용해야하는 경우. 이것은 후자의 Timer가 Swing 이벤트 모델과 잘 작동하고 스레드 충돌을 방지하기 때문에 매우 중요합니다. Swing Timer Tutorial

기타 문제 : 고정 크기 배열을 사용하면 4 개 이상의 스레드가 실행되기를 원할 경우 색인 범위를 벗어날 수 있습니다. ArrayList를 대신 사용하십시오.