简体   繁体   中英

I'm making a command line music player in java, and my 'skip' button is sometimes skipping more than once

So, basically, my code currently is just taking in one argument from the commmand line, which is the folder in which all of the wave files are to play in the playlist. I have another thread which takes in user input. When the user inputs 'skip' it will continue through the for loop of items. It all works fine, but, if i type skip, and hit enter, sometimes it skips twice. I presume it has something to do with the threading business. Here's my code.

 package com.thechief.music;

 import java.io.File;
 import java.io.FilenameFilter;
 import java.util.Scanner;

 import javax.sound.sampled.AudioInputStream;
 import javax.sound.sampled.AudioSystem;
 import javax.sound.sampled.Clip;

 public class Player {

public static int index = 0; // The current clip playing
public static Clip[] clip;

public static void main(String[] args) throws Exception {
    Scanner scanner = new Scanner(System.in);

    FilenameFilter textFilter = new FilenameFilter() {
        public boolean accept(File dir, String name) {
            return name.toLowerCase().endsWith(".wav");
        }
    };

    File[] files = new File(args[0]).listFiles(textFilter);
    clip = new Clip[files.length];

    Runnable b = new Runnable() {
        public void run() {
            while (true) {
                String command = scanner.next();
                if (command.equals("skip")) {
                    getCurrentClip().stop();
                } else if (command.equals("back")) {
                    getCurrentClip().stop();
                    if (index > 0) {
                        index -= 2;
                    } else {
                        System.out.println("Cannot go back further than the first item.");
                    }
                }
            }
        }
    };
    Thread second = new Thread(b);
    second.start();

    for (index = 0; index < clip.length; index++) {
        if (index < 0) index = 0;
        clip[index] = AudioSystem.getClip();
        if (index < 0) index = 0;
        AudioInputStream ais = AudioSystem.getAudioInputStream(files[index]);
        if (!getCurrentClip().isOpen()) {
            getCurrentClip().open(ais);
        } else {
            getCurrentClip().close();
            getCurrentClip().open(ais);
        }

        getCurrentClip().start();

        System.out.println("Now Playing: " + files[index].getName() + ", Time Left: "
                + (getCurrentClip().getMicrosecondLength() / 1000000.f) + " seconds.");

        while (getCurrentClip().getMicrosecondLength() != getCurrentClip().getMicrosecondPosition()
                || getCurrentClip().isActive()) {
            if (!getCurrentClip().isActive()) {
                break;
            }
        }
    }

    System.out.println("Playlist completed.");

    scanner.close();
    second.join();
}

public static Clip getCurrentClip() {
    return clip[index];
}
 }

Here:

public static int index = 0; // The current clip playing

That index field is used and updated by more than one thread. That means: anything can happen.

A first step: use AtomicInteger instead of int here.

And the real answer of course: you have to research what you are doing. Just adding new Thread().start() here or there without knowing and understanding what you are doing is a nothing but a recipe to run into all sorts of unpredictable behavior. It is super simple: when mutable data is shared between multiple threads, then you absolutely must ensure that the necessary precautions are in place.

To give a bit more guidance: to prevent things like if (index < 0) index = 0; to enable races .

Meaning: one thread sees index=1 for example, and then turns index to 0. But at the same time, another thread tried to read index, and used wrong intermediate content.

When you turn that index into an AtomicInteger , you can start doing things like:

synchronized(index) {
  if (index ...
    index = ...
}

for example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM