Я делаю музыкальный проигрыватель командной строки в Java, и моя кнопка «Пропустить» иногда пропускает более одного раза - PullRequest
0 голосов
/ 04 ноября 2018

Итак, по сути, мой код в настоящий момент принимает только один аргумент из строки команды, которая является папкой, в которой все файлы wave должны воспроизводиться в списке воспроизведения. У меня есть другая тема, которая принимает пользовательский ввод. Когда пользователь вводит «пропустить», он будет продолжать цикл for. Все работает нормально, но, если я набираю skip и нажимаю enter, иногда пропускается дважды. Я предполагаю, что это как-то связано с бизнесом потоков. Вот мой код.

 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];
}
 }

1 Ответ

0 голосов
/ 04 ноября 2018

Здесь:

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

Это поле индекса используется и обновляется несколькими потоками. Это значит: все может случиться.

Первый шаг: используйте AtomicInteger вместо int здесь.

И реальный ответ, конечно: вы должны исследовать, что вы делаете. Просто добавьте new Thread().start() здесь или там без знания и понимания того, что вы делаете, - не что иное, как рецепт столкнуться со всеми видами непредсказуемого поведения. Это очень просто: когда изменяемые данные совместно используются между несколькими потоками, тогда вы абсолютно должны обеспечить соблюдение необходимых мер предосторожности.

Чтобы дать немного больше указаний: запретить такие вещи, как if (index < 0) index = 0;, чтобы включить гонки .

Значение: один поток видит, например, index = 1, а затем устанавливает индекс в 0. Но в то же время другой поток пытался прочитать индекс и использовал неправильное промежуточное содержимое.

Когда вы превращаете этот индекс в AtomicInteger, вы можете начать делать такие вещи, как:

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

например.

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