IllegalThreadStateException? Не знакомы с потоками - PullRequest
3 голосов
/ 11 марта 2012

У меня есть работающая java-программа, простой mp3-плеер.

Все работает, может пропустить треки и т. Д., Но после нескольких пропусков (особенно кнопка возврата (предыдущий трек) я всегда получаюa 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 ]

8 голосов
/ 11 марта 2012

Проблема здесь:

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);
    }
}
4 голосов
/ 11 марта 2012

Прежде всего, вам необходимо ознакомиться с потоками, так как этот проект, над которым вы работаете, использует их! Ваш учебник класса может охватывать эту тему. Внимательно прочитайте. Темы ОЧЕНЬ важны. Если ваш учебник не понятен, вы также можете прочитать официальный учебник Java .

Вернуться к вашему вопросу. Каждый экземпляр вашего класса MP3 работает в отдельном потоке. Поток MP3 отделен от выполнения основной программы (имеется в виду поток, выполняющий основной метод), а пользовательский интерфейс Swing также выполняется в отдельном потоке.

Ваша ошибка указывает на то, что, чтобы процитировать Javadocs для java.lang.IllegalThreadStateException:

поток не находится в соответствующем состоянии для запрошенной операции. См., Например, методы suspend и resume в классе Thread.

Вот некоторые вещи, на которые стоит посмотреть:

  1. Ваш класс таймера может остановиться и запустить поток MP3. Он вызывает playSong (текущий); и stopPlayback (). Есть ли другой класс, также вызывающий эти методы? Ваша ошибка была вызвана пользовательским событием: pa2.MP3Random $ ButtonListener.actionPerformed (MP3Random.java:373) Вы нажали кнопку до того, как тема была готова к игре?
  2. В общем, вам нужно убедиться, что два потока не мешают друг другу. Классическим примером могут быть два потока, которые изменяют один и тот же список. Если первый поток удаляет элемент из списка, в то время как второй поток выполняет итерацию по списку (используя итератор или для каждого цикла), будет выдано исключение.
  3. Можете ли вы протестировать данные классы для воспроизведения mp3 без графического интерфейса? Просто статический вызов метода. Можно ли заставить плеер работать?

Пункт 2 в моем ответе, вероятно, не связан с вашей проблемой - это просто важно понимать при работе с потоками. Например, если список доступных песен должен был измениться в вашей PlaylistPanel (несколько потоков могли бы изменить его), то вам нужно было бы синхронизировать часть этого класса. Это заставляет поток ждать, если другой поток выполняет синхронизированный метод. Ваша проблема пытается перезапустить «мертвый» поток Посмотрите на JavaDocs для потока :

Никогда не разрешено начинать поток более одного раза. В частности, поток не может быть перезапущен после завершения выполнения.

Итак, чтобы запустить поток, вы вызываете start. Начать звонки. Этот поток теперь будет «запускаться» одновременно с другими потоками, пока run () не завершится. И как только он заканчивается, мы закончили с этим потоком. Если мы хотим, чтобы один и тот же поток воспроизводил несколько песен, нам нужно реализовать это поведение. Но метод запуска, который вы опубликовали (который, я думаю, вы не написали; он был дан как часть этого задания), очень прост. Он вызывает player.play(); и когда palay завершается, поток завершается.

Я думаю, что последняя строка метода run () должна быть player = null, чтобы метод isPlaying () работал правильно.

2 голосов
/ 11 марта 2012

Просто предположение, но: возможно ли, что вы вызываете методы из AWT-виджетов из ваших потоков?Для SWT это не будет работать, например, вызовы виджетов должны вызываться из GUI-потока, то есть потока, который их создал.Не уверен, что это то же самое для AWT, но его стоит проверить ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...