【问题标题】:IllegalThreadStateException? Not Familiar With Threads非法线程状态异常?不熟悉线程
【发布时间】:2012-03-28 03:14:14
【问题描述】:

我有一个可用的 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)

【问题讨论】:

    标签: java multithreading swing exception


    【解决方案1】:

    首先,您需要熟悉线程,因为您正在处理的这个项目使用它们!您的课堂教科书可能涵盖该主题。仔细阅读。线程非常重要。如果你的课本不清楚,也可以read the official Java tutorial

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

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

    线程未处于请求操作的适当状态。 例如,请参见 Thread 类中的挂起和恢复方法。

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

    1. 您的计时器类可以停止和启动 MP3 线程。它调用 playSong(current);和停止播放()。是否有另一个类也调用这些方法?您的错误是由用户事件触发的:pa2.MP3Random$ButtonListener.actionPerformed(MP3Random.java:373) 您是否在线程准备好播放之前点击了按钮?
    2. 一般情况下,您需要确保两个线程不会相互干扰。一个典型的例子是两个线程都修改同一个列表。如果第一个线程从列表中删除一个项目,而第二个线程正在迭代列表(使用迭代器或针对每个循环),则会引发异常。
    3. 您能否测试给定的类以在没有 GUI 的情况下播放 mp3?只是一个静态方法调用。你能让播放器工作吗?

    我的回答中的第 2 点可能与您的问题无关 - 在使用 Threads 时了解这一点很重要。例如,如果要在 PlaylistPanel 中更改可用歌曲列表(多个线程可以更改它),那么您需要使该类的一部分同步。如果另一个线程正在运行同步方法,这将强制线程等待。你的问题是试图重新启动一个“死”的线程查看JavaDocs for Thread

    多次启动一个线程是不合法的。特别是,一个 线程一旦完成执行就可能不会重新启动。

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

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

    【讨论】:

    • 您好,Thorn,感谢您的帮助!按下按钮后会立即弹出错误(不是在第一次按下按钮时,而是在几次下一步/后退,停止开始点击之后)我理解你的第二点,这是有道理的,虽然我不知道如何从代码深处对其进行故障排除。
    • @Wangagat 您是否在每次需要播放歌曲时都创建一个新的 MP3 实例?
    • 这是一个有趣的任务。适合什么课?
    • @Thorn, It's not immediately clear to me what the root cause of this error is 堆栈跟踪是一个很好的起点:) 请参阅上面的答案。
    【解决方案2】:

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

    【讨论】:

    • 这不太可能。最可能的答案是已经说过的。每次需要播放歌曲时都必须创建一个新的 mp3 对象。我无法编译给定的代码。我们缺少类:MainPanel 扩展 JPanel 和 PlaylistPanel 扩展 JPanel
    • @Thorn 正确,请参阅我对 GETah 答案的评论。
    【解决方案3】:

    问题出在这里:

    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.Startjava doc 说:

    抛出:IllegalThreadStateException - 如果线程已经 开始了。

    基本上,一个线程不能多次启动。每当您在已由 MP3.Play() 启动的 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);
        }
    }
    

    【讨论】:

    • 我不认为是这种情况,因为他将 MP3 实例传递给 MP3Random.playSong() 方法。如果你的理论成立,他每次都必须传递相同的 MP3 实例......注意,MP3 已经是一个线程!
    • 每当我按下后退/下一个/播放按钮播放之前播放过的歌曲时,都会发生错误。由于我无法编辑 mp3 类,我该如何修改自己的代码?
    • @Wangagat 那么 GETah 是对的。每次播放歌曲时,您都需要创建 MP3-Class 的新实例。您在同一个实例上多次调用MP3.play() - 所以您正在尝试启动一个已经启动的线程。这不起作用。
    • 啊...我明白你的意思了。这将如何工作,因为我正在创建一个播放列表,该列表填充附加到 JList 的 DefaultListModel。选定歌曲的数组已经为每个选定的文件创建了一个 MP3 类的实例,以便填充数组。
    • @Wangagat 刚刚用一些代码 sn-p 更新了我的帖子。请查看更新以了解如何更改代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-13
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    相关资源
    最近更新 更多