简体   繁体   English

Thread.sleep()的意外行为

[英]Unexpected behaviour with Thread.sleep()

I have constructed a simple program to play a song. 我构建了一个简单的程序来播放一首歌。

import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import java.io.File;
import javax.swing.*;
import java.awt.*;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.application.Platform;
import javafx.scene.Group; 

public class Fade {
    private void initAndShowGUI() {
        // This method is invoked on Swing thread
        JFrame frame = new JFrame("FX");
        final JFXPanel fxPanel = new JFXPanel();
        frame.add(fxPanel);
        frame.setVisible(true);

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                initFX(fxPanel);
            }
        });
    }

    private void initFX(JFXPanel fxPanel) {
    // This method is invoked on JavaFX thread
        Group root = new Group(); 
        Scene scene = new Scene(root, 500, 500, true);
        fxPanel.setScene(scene);

        try {
            String bip = new File("./Sound/Welcome To The Show - L1-5.mp3").toURI().toString();
            Media hit = new Media(bip);
            MediaPlayer mediaPlayer = new MediaPlayer(hit);
            mediaPlayer.play();

            Thread.sleep(10000);
            System.out.println("Fade");
        } catch (Exception e) {
            System.out.println("Exception");
            System.out.println(e);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Fade().initAndShowGUI();
            }
        });
    }
}

However when this code is run the Thread.sleep(10000) runs before the song starts playing instead of the song starting playing then 10 seconds later fade is printed out to the console. 但是,当运行此代码时, Thread.sleep(10000)在歌曲开始播放之前运行而不是开始播放的歌曲,然后10秒后fade打印到控制台。 How may I fix this? 我该如何解决这个问题?

You are blocking the JavaFX Application Thread, so it cannot do its normal work (which presumably includes processing the media player's instruction to start) until your method completes. 您正在阻止JavaFX应用程序线程,因此它无法执行其正常工作(可能包括处理媒体播放器的指令以启动),直到您的方法完成。 You should never block this thread, as it is guaranteed to make the UI unresponsive. 您永远不应该阻止此线程,因为它可以保证UI不响应。

The simplest way to implement a pause in JavaFX is to use a PauseTransition : 在JavaFX中实现暂停的最简单方法是使用PauseTransition

MediaPlayer mediaPlayer = new MediaPlayer(hit);
mediaPlayer.play();

// never do this:
//Thread.sleep(10000);

PauseTransition pause = new PauseTransition(Duration.millis(10000));
pause.setOnFinished(e -> {
    System.out.println("Fade");
});
pause.play();

(As an aside, I assume your real application has some reason to mix swing and JavaFX. Otherwise you should make this a pure JavaFX app.) (顺便说一句,我认为你的真实应用程序有一些理由混合swing和JavaFX。否则你应该把它变成一个纯JavaFX应用程序。)

Operating on a MediaPlayer is asynchronous. MediaPlayer上操作是异步的。 This explains why "Fade" is printed before the actual music begins. 这解释了为什么在实际音乐开始之前打印"Fade" From the documentation : 文档

The operation of a MediaPlayer is inherently asynchronous. MediaPlayer的操作本质上是异步的。 A player is not prepared to respond to commands quasi-immediately until its status has transitioned to MediaPlayer.Status.READY , which in effect generally occurs when media pre-roll completes. 玩家不准备立即响应命令,直到其状态转换为MediaPlayer.Status.READY ,这实际上通常在媒体预滚动完成时发生。 Some requests made of a player prior to its status being READY will however take effect when that status is entered. 但是,在状态为READY之前对玩家提出的某些请求将在输入该状态时生效。 These include invoking play() without an intervening invocation of pause() or stop() before the READY transition, as well as setting any of the autoPlay , balance , mute , rate , startTime , stopTime , and volume properties. 这些包括在READY转换之前调用play()而不调用pause()stop() ,以及设置autoPlaybalancemuteratestartTimestopTimevolume属性中的任何一个。

You can control if the player is actually playing by polling its status . 您可以通过轮询其状态来控制玩家是否实际正在玩游戏。 From play() (emphasis mine): play() (强调我的):

Starts playing the media. 开始播放媒体。 If previously paused, then playback resumes where it was paused. 如果之前暂停,则播放将在暂停时恢复。 If playback was stopped, playback starts from the startTime. 如果停止播放,则从startTime开始播放。 When playing actually starts the status will be set to MediaPlayer.Status.PLAYING . 实际播放时,状态将设置为MediaPlayer.Status.PLAYING

To register a callback when the player starts playing, you can hook into the onPlayingProperty by adding a change listener or directly setting an event handler by calling setOnPlaying(runnable) 要在播放器开始播放时注册回调,您可以通过添加更改侦听器或通过调用setOnPlaying(runnable)直接设置事件处理程序来挂接到onPlayingProperty

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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