IllegalThreadStateException?不熟悉线程

时间:2012-03-11 12:27:17

标签: java multithreading swing exception

我有一个有效的java程序,一个简单的mp3播放器。

一切正常,可以跳过轨道等......但经过几次跳过(特别是后退按钮(上一首曲目),我总是得到一个IllegalThreadStateException。我不熟悉线程,所以我是不知道该怎么做。

这是一个学校作业,MP3课程已经发给我们。 (不能修改)

任何提示将不胜感激!谢谢!

MP3类(无法修改):

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import javazoom.jl.player.Player;


public class MP3 extends Thread {
  private final File mp3_file;
  private Player player; 

  public MP3(String mp3_path) {
    mp3_file = new File(mp3_path);
}

  public MP3(File mp3) {
    mp3_file = mp3;
}

    public void play() {
    try {
        FileInputStream fis     = new FileInputStream(mp3_file);
        BufferedInputStream bis = new BufferedInputStream(fis);
        player = new Player(bis);
    }
    catch (Exception e) {
        System.out.println("Problem playing file " + mp3_file);
        System.out.println(e);
    }

    // run in new thread to play in background
    start();  // Instructs JVM to call run() in separate thread

  }

  public boolean isPlaying() {
    if (player == null)
        return false;
    else {
        return !player.isComplete();
    }

  }

  public void run() {
    try { player.play(); }
    catch (Exception e) { System.out.println(e); }
  }


      public void quit() {
    if (player != null) {
        player.close(); 
        player = null;
    }
  }

  public String toString() {
    return mp3_file.toString();
  }
}

我的代码:

import javax.swing.*;

public class MP3Random extends JFrame {

private JPanel backgroundPanel;
private PlaylistPanel playlistPanel;
private MainPanel mainPanel; 

int trackTime;
private MP3 current;

private ButtonListener buttonListener;
private TimerListener timerListener;

private Timer timer;
private boolean playButtonStatus;

public MP3Random() {

    buttonListener = new ButtonListener();
    timerListener = new TimerListener();

    backgroundPanel = new JPanel();
    mainPanel = new MainPanel();
    playlistPanel = new PlaylistPanel();

    timer = new Timer(1000, timerListener);
    timer.setInitialDelay(0);
    playButtonStatus = false;

    setMinimumSize(new Dimension(650, 400));
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    getContentPane().setLayout(new BorderLayout(0, 0));

    backgroundPanel.setLayout(new BorderLayout(0, 0));
    backgroundPanel.setBorder(null);
    backgroundPanel.add(playlistPanel, BorderLayout.CENTER);
    backgroundPanel.add(mainPanel, BorderLayout.NORTH);

    getContentPane().add(backgroundPanel);
    setVisible(true);
}

private void playSong(MP3 current) {
    ImageIcon stopIcon = new ImageIcon(MP3Random.class.getResource("/pa2/icons/stop.png"));

      playlistPanel.playList.setSelectedIndex(playlistPanel.listModel.indexOf(current));
    mainPanel.playButton.setIcon(stopIcon);
    trackTime = 0;
    current.play();
    timer.restart();
    mainPanel.trackTitleLabel.setText(getTrackTitle(current.toString()));
}

private void stopPlayback() {
    try {
        current.quit();
        timer.stop();
        playButtonStatus = false;
        mainPanel.trackTitleLabel.setText("");
        mainPanel.trackTimeLabel.setText("");
        mainPanel.playButton.setIcon(mainPanel.playIcon);
    }
    catch (Exception e) {};
}

private String getTrackTitle (String filename) {
    return filename.substring(filename.lastIndexOf('/')+1, filename.lastIndexOf(".mp3"));
}

private String formatTime(int durationInSeconds) {

    int minutes = durationInSeconds / 60;
    int seconds = durationInSeconds % 60;

    return ( (minutes < 10 ? "0" : "") + minutes
            + ":" + (seconds< 10 ? "0" : "") + seconds );
}

//Panel containing track display/time, media control buttons
private class MainPanel extends JPanel {...}

//Panel containing JList and add/remove from playlist buttons
private class PlaylistPanel extends JPanel {...}

private class ButtonListener implements ActionListener {

    File[] filesSelected;
    MP3[] mp3List;
    Random generator = new Random();

    public void actionPerformed (ActionEvent event) {

        if (event.getSource() == playlistPanel.addButton) {
            playlistPanel.fileChooser = new JFileChooser();
            playlistPanel.fileChooser.setMultiSelectionEnabled(true);

            //FileFilter only allows *.mp3
            playlistPanel.fileChooser.setAcceptAllFileFilterUsed(false);
            playlistPanel.fileChooser.setFileFilter(new FileFilter() {

                public boolean accept(File f) {
                    if (f.isDirectory())
                        return true;

                    String extension = f.toString().substring(f.toString().lastIndexOf('.')+1);
                    if (extension != null) {
                        if (extension.equals("mp3"))
                            return true;
                        else
                            return false;
                    }
                    return false;
                }

                public String getDescription() {
                    return "*.mp3";
                }
            });

            if (playlistPanel.fileChooser.showOpenDialog(MP3Random.this) == JFileChooser.APPROVE_OPTION) {

                filesSelected = playlistPanel.fileChooser.getSelectedFiles();
                mp3List = new MP3[filesSelected.length];

                mainPanel.playButton.setEnabled(true);
                playlistPanel.removeButton.setEnabled(true);

                //more than 1 file selected
                if (mp3List.length > 1) {
                    mainPanel.shuffleButton.setEnabled(true);
                    mainPanel.nextButton.setEnabled(true);
                }
                for (int i = 0; i < mp3List.length; i++)
                    playlistPanel.listModel.addElement(mp3List[i] = new MP3(filesSelected[i]));
                current = (MP3) playlistPanel.listModel.get(0);
                playlistPanel.playList.setSelectedIndex(playlistPanel.listModel.indexOf(current));
            }
        }

        //remove button
        if (event.getSource() == playlistPanel.removeButton) {
            Object[] temp = playlistPanel.playList.getSelectedValues();
            for (Object f : temp) {
                playlistPanel.listModel.removeElement(f);
            }

           //1 song in list
           if (playlistPanel.listModel.getSize() == 1) {
               mainPanel.backButton.setEnabled(false);
               mainPanel.nextButton.setEnabled(false);
               mainPanel. shuffleButton.setEnabled(false);
           }

           //no songs in list
           if (playlistPanel.listModel.getSize() == 0) {
               playlistPanel.removeButton.setEnabled(false);
               mainPanel.playButton.setEnabled(false);             
               mainPanel.backButton.setEnabled(false);
               mainPanel.nextButton.setEnabled(false);
               mainPanel.shuffleButton.setEnabled(false);
               current = null;
            }
        }

        //play button
        if (event.getSource() == mainPanel.playButton) {

            //if song not playing
            if (!playButtonStatus) {
                if (!playlistPanel.playList.isSelectedIndex(playlistPanel.listModel.indexOf(current)))
                    current = (MP3) playlistPanel.playList.getSelectedValue();
                playSong(current);                  
                playButtonStatus = true;
            }

            //if song is playing
            else
                stopPlayback();
        }

        //next button
        if (event.getSource() == mainPanel.nextButton) {
            if (!mainPanel.backButton.isEnabled())
                mainPanel.backButton.setEnabled(true);

            if (current.isPlaying()) {
                current.quit();
                current = (MP3) playlistPanel.listModel.get(playlistPanel.listModel.indexOf(current)+1);
                playSong(current);
            }
            else {
                current = (MP3) playlistPanel.listModel.get(playlistPanel.listModel.indexOf(current)+1);
                playlistPanel.playList.setSelectedIndex(playlistPanel.listModel.indexOf(current));
            }

            if (playlistPanel.listModel.indexOf(current) == playlistPanel.listModel.size() - 1)
                mainPanel.nextButton.setEnabled(false);
        }

        //back button
        if (event.getSource() == mainPanel.backButton) {

            if (!mainPanel.nextButton.isEnabled())
                mainPanel.nextButton.setEnabled(true);  

            if (current.isPlaying()) {
                current.quit();
                current = (MP3) playlistPanel.listModel.get(playlistPanel.listModel.indexOf(current)-1);
                playSong(current);
            }
            else {
                current = (MP3) playlistPanel.listModel.get(playlistPanel.listModel.indexOf(current)-1);
                playlistPanel.playList.setSelectedIndex(playlistPanel.listModel.indexOf(current));
            }

            if (playlistPanel.listModel.indexOf(current) == 0)
                mainPanel.backButton.setEnabled(false);
        }

        //shuffle jlist
        if (event.getSource() == mainPanel.shuffleButton) {
            if (playlistPanel.listModel.size() > 1) {
                int n = playlistPanel.listModel.getSize();
                while (n > 1) {
                    int k = generator.nextInt(n);
                    n--;                 
                    MP3 tempMP3 = (MP3) playlistPanel.listModel.elementAt(n);
                    playlistPanel.listModel.set(n,playlistPanel.listModel.elementAt(k));
                    playlistPanel.listModel.set(k, tempMP3);
                    current = (MP3) playlistPanel.listModel.get(0);
                    playlistPanel.playList.setSelectedIndex(playlistPanel.listModel.indexOf(current));
                }
            }
        }
    }
}

private class TimerListener implements ActionListener {

    public void actionPerformed(ActionEvent event) {

        if (playlistPanel.listModel.indexOf(current) > 0)
            mainPanel.backButton.setEnabled(true);
        if (playlistPanel.listModel.indexOf(current) == playlistPanel.listModel.size()-1)
            mainPanel.nextButton.setEnabled(false);
        if (!current.isPlaying()) {
            if (playlistPanel.listModel.size() > 1 && playlistPanel.listModel.indexOf(current) < playlistPanel.listModel.size()-1) {
                current = (MP3) playlistPanel.listModel.get(playlistPanel.listModel.indexOf(current)+1);
                playSong(current);
            }
            else
                stopPlayback();
        }
        else {
            mainPanel.trackTimeLabel.setText(formatTime(trackTime));
            trackTime++;
        }
    }
}

public static void main(String[] args) throws Exception {

    MP3Random instance = new MP3Random();
}
}

错误:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:656)
at pa2.MP3.play(MP3.java:41)
at pa2.MP3Random.playSong(MP3Random.java:68)
at pa2.MP3Random.access$4(MP3Random.java:62)
at pa2.MP3Random$ButtonListener.actionPerformed(MP3Random.java:373)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2351)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at     javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:6373)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
at java.awt.Component.processEvent(Component.java:6138)
at java.awt.Container.processEvent(Container.java:2085)
at java.awt.Component.dispatchEventImpl(Component.java:4735)
at java.awt.Container.dispatchEventImpl(Container.java:2143)
at java.awt.Component.dispatchEvent(Component.java:4565)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4621)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4282)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4212)
at java.awt.Container.dispatchEventImpl(Container.java:2129)
at java.awt.window.dispatchEventImpl(window.java:2478)
at java.awt.Component.dispatchEvent(Component.java:4565)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:679)
at java.awt.EventQueue.access$000(EventQueue.java:85)
at java.awt.EventQueue$1.run(EventQueue.java:638)
at java.awt.EventQueue$1.run(EventQueue.java:636)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:98)
at java.awt.EventQueue$2.run(EventQueue.java:652)
at java.awt.EventQueue$2.run(EventQueue.java:650)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:649)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

3 个答案:

答案 0 :(得分:8)

问题在于:

public void play() {
  try {
    FileInputStream fis     = new FileInputStream(mp3_file);
    BufferedInputStream bis = new BufferedInputStream(fis);
    player = new Player(bis);
  }
  catch (Exception e) {
    System.out.println("Problem playing file " + mp3_file);
    System.out.println(e);
  }
  // run in new thread to play in background
  start();  // <======== PROBLEM
}

Thread.Start java doc说:

  

抛出:IllegalThreadStateException - 如果线程已经存在   启动。

基本上,一个线程不能多次启动。只要您在已Play已启动的MP3实例上致电MP3.Play(),您就会收到此异常 我建议的是在调用MP3.Play时创建一个新线程来播放你的音轨。 玩家类看起来像:

public class MP3Player extends Thread {
   public void PlayFile(String soundFile){
      //... Add player logic here
   }
   public void StopPlaying(){
      //.. Stop playing and gracefully exit this thread
   }
}

在MP3课程中:

public class MP3{
    MP3Player currentPlayer = null;
    // ...
    public void play() {
       if(currentPlayer != null) currentPlayer.StopPlaying();
       currentPlayer = new MP3Player();
       currentPlayer.PlayFile(mp3_file);
    }
}

答案 1 :(得分:4)

首先,您需要熟悉Threads,因为您正在使用的项目使用它们!您的课程教材可能涵盖此主题。仔细阅读。线程非常重要。如果您的教科书不清楚,您还可以read the official Java tutorial

回到你的问题。 MP3类的每个实例都在一个单独的Thread中运行。 MP3线程与主程序执行(即运行main方法的线程)分开,并且swing UI也在单独的线程中运行。

您的错误表明引用java.lang.IllegalThreadStateException的Javadoc:

  

线程未处于所请求操作的适当状态。   例如,请参阅Thread。类中的suspend和resume方法。

以下是一些要注意的事项:

  1. 您的计时器类可以停止并启动MP3线程。它叫playSong(当前);和stopPlayback()。还有另一个类也调用这些方法吗?您的错误是由用户事件触发的:pa2.MP3Random $ ButtonListener.actionPerformed(MP3Random.java:373) 在线程准备好播放之前,您是否单击了按钮?
  2. 通常,您需要确保两个线程不会相互干扰。一个典型的例子是两个线程都修改相同的列表。如果第一个Thread从列表中删除一个项目,而第二个线程在列表上迭代(使用Iterator或每个循环),则会抛出异常。
  3. 你可以测试一下没有GUI播放mp3的给定类吗?只是一个静态方法调用。你能让这名球员上班吗?
  4. 我的答案中的第2点可能与您的问题无关 - 在使用Threads时理解这一点非常重要。例如,如果要在PlaylistPanel中更改可用歌曲列表(多个线程可以更改它),那么您需要使该类的一部分同步。如果另一个线程正在运行同步方法,则强制线程等待。您的问题是尝试重新启动“已死”的线程查看JavaDocs for Thread

      

    不止一次启动线程永远不合法。特别是,a   一旦完成执行,线程可能无法重新启动。

    所以要启动该线程,请调用start。开始通话。该线程现在将与其他线程同时“运行”,直到run()终止。一旦它终止,我们就完成了这个线程。如果我们想要相同的线程播放多首歌曲,我们需要实现此行为。但是你发布的run方法(我认为你没有写;它是作为这个任务的一部分给出的)非常简单。它调用player.play();,当palay终止时,线程完成。

    我认为run()方法的最后一行应该是player = null,这样isPlaying()方法才能正常工作。

答案 2 :(得分:2)

只是一个猜测,但是:可能是,你在线程中调用AWT-Widgets上的方法?对于SWT,这不起作用,例如,必须从GUI-Thread调用widget调用,即创建它们的线程。 不确定AWT是否相同,但值得检查...