IllegalThreadStateException? Not familiar with the topics

I have a working Java program, a simple mp3 player.

Everything works, can skip tracks, etc., but after a few skips (especially the back button (previous track), I always get IllegalThreadStateException

. I'm not familiar with streams, so I'm not sure what to do.

This is for a school assignment and the MP3 class is provided to us. (cannot be changed)

Any advice would be greatly appreciated! Thank!

MP3 class (cannot be changed):

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();
  }
}

      

My code:

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();
}
}

      

Mistake:

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


source to share


3 answers


The problem is here:

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
}

      

The Thread.Start

java doc says:

Throws: IllegalThreadStateException - if the thread was already started.



Basically, a thread cannot run more than once. You will get this exception when you call Play

on an instance MP3

that has already been started MP3.Play()

I suggest creating a new stream to play your track whenever called MP3.Play

. The player class might look like this:

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

      

And in the MP3 class:

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

      

+7


source


First of all, you need to get familiar with Threads, as this project you are working on uses them! Your class's textbook may cover this topic. Let him read carefully. Topics are very important. If your tutorial is unclear, you can also read the official Java tutorial .

Let's get back to your question. Each instance of your MP3 class runs on a separate thread. The MP3 stream is separate from the main program execution (which means the thread that runs the main method) and the swing UI runs in a separate thread as well.

Your error indicates that quoting the Javadocs for java.lang.IllegalThreadStateException

:

the thread is not in the correct state for the requested operation. See, for example, the suspend and resume methods in the Thread class.

Here's what to look at:



  • Your timer can stop and start the MP3 stream. It calls playSong (current); and stopPlayback (). Is there another class that calls these methods? Your error was triggered by a custom event: pa2.MP3Random $ ButtonListener.actionPerformed (MP3Random.java:373) Did you press the button before the Thread was ready to play?
  • In general, you need to make sure that the two strands do not interfere with each other. A classic example would be two threads modifying the same list. If the first thread removes an item from the list while the second thread is iterating over the list (using an Iterator or for each loop), an exception will be thrown.
  • Can you check out these classes for playing mp3 without a GUI? Just a call to a static method. Can you get the player to work?

Point # 2 in my answer is probably not related to your problem - it's just important to understand when dealing with Threads. For example, if the list of available songs were to change in your PlaylistPanel (multiple threads might change it), you will need to make part of this class synchronized. This makes the Thread wait for another thread to execute the synchronized method. Your problem is trying to restart the thread, "dead". Have a look at JavaDocs for Thread :

It is not possible to run a thread more than once. In particular, a thread cannot be restarted after completion of execution.

So, to start a thread, you call start. Launch launch. This thread will now "run" concurrently with other threads until run () is complete. And as soon as it ends, we are done with this flow. If we wanted the same stream to play multiple songs, we hurt the need to implement this behavior. But the startup method you posted (which I think you didn't write, it was given as part of this assignment) is very simple. It calls player.play();

, and when palay exits, the thread is executed.

I think the last line of the run () method should be player = null

so that the isPlaying () method will work correctly.

+4


source


Easy to guess, but: Maybe you are calling methods on AWT-Widgets from your threads? This does not work for SWT, for example, call-calls must be called from the GUI-Thread, i.e. The thread that created them. Not sure if they are the same for AWT, but worth checking out ...

+2


source







All Articles