Multithreading 等待();睡眠()不象想象的那样工作
在IntelliJ中使用JavaFX8.0和JRE 1.8.0 u45,我创建了一个基本像素编辑器应用程序。我有两个窗口(阶段)。一个是放置在Multithreading 等待();睡眠()不象想象的那样工作,multithreading,javafx-8,wait,sleep,Multithreading,Javafx 8,Wait,Sleep,在IntelliJ中使用JavaFX8.0和JRE 1.8.0 u45,我创建了一个基本像素编辑器应用程序。我有两个窗口(阶段)。一个是放置在网格窗格中的圆形对象的32x128矩阵,另一个是工具窗口;我有一个Controller.java。使用鼠标,“工具”窗口提供绘制线条、矩形等的工具以及设置、文件和播放列表的菜单。“文件”菜单向用户显示“打开”、“另存为”和“删除”。要查看保存的像素艺术文件,用户单击“打开”,然后通过JFileChooser,打开所选文件,并使用以下方法显示每个圆的指定颜色
网格窗格
中的圆形
对象的32x128矩阵,另一个是工具窗口;我有一个Controller.java
。使用鼠标,“工具”窗口提供绘制线条、矩形等的工具以及设置、文件和播放列表的菜单。“文件”菜单向用户显示“打开”、“另存为”和“删除”。要查看保存的像素艺术文件,用户单击“打开”,然后通过JFileChooser
,打开所选文件,并使用以下方法显示每个圆的指定颜色:
public static void openFile( String pathName) throws IOException {
path = Paths.get(pathName);
pixelByteArray = Files.readAllBytes(path);
int cnt = 0;
for (int r = 0; r < row; r++) {
for (int c = 0; c < col; c++) {
String hexRGB = String.format("#%02X%02X%02X",
pixelByteArray[cnt++], //red
pixelByteArray[cnt++], //green
pixelByteArray[cnt++]); //blue
Color color = Color.valueOf(hexRGB);
pixelArray[r][c].setFill(color);
}
}
String fileName = path.getFileName().toString();
window.setTitle(MessageFormat.format("Pixel Array {0} x {1} File: {2}", Integer.toString(row), Integer.toString(col), fileName));
} // openFile
我第一次使用了wait(5000)
,但无法编译,因为我需要一个静态方法。wait()
方法不会在静态方法中运行。然后我尝试编译sleep(5000)
,但令我困惑的是,只有ArrayList
中的最后一个文件会显示出来。所有像素艺术文件将正确显示setTitle()
,并暂停约5秒,但在5秒过后,圆圈将不会更改为指定的颜色,最后一个文件除外。openFile()
中的for
循环setFill(color)
进程似乎已暂停,即使setTitle()
已正确执行,这是在setFill(color)
进程之后
我是Java和JavaFX新手,从未在这个程序或任何其他程序中直接创建过任何线程,但研究可能的问题意味着问题可能与线程有关
这个问题有经典的解决方法吗?谢谢你的帮助
在研究了下面的参考资料和建议的解决方案后,我无法解决这个问题。我尝试了两个代码更改。第一个是到上面的for循环代码:
for (File selectedFile : selectedFiles) {
Platform.runLater(() -> {
try {
openFile(selectedFile.getPath());
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
});
第二个更改是上面的openFile(路径名):
我得到了与上面描述的相同的结果,只显示了最后一个文件。如果我只是在Arraylist
中选择一个文件,它将显示,即:
if (selectedFiles != null) {
File playFile = selectedFiles.get(0);
openFile(playFile.getPath());
System.out.println("\n File 1 = " + playFile.getPath());
}
现在,如果我添加睡眠(5000)
:
它将在5秒后显示像素艺术文件。我不明白的是为什么它似乎“跳过”了pixelArray[r][c].setFill(color))
将所有圆圈设置为保存的颜色,但执行openFile(路径名)
中的以下和最后一条语句,即setTitle(…)
?这就像sleep(5000)
阻止pixelArray[r][c].setFill(color))代码>但没有别的吗
为什么我可以openFile(pathname)
只针对一个结果正确的文件,而不是两个或更多顺序的文件
我还在web上发布了两个UI窗口:。我认为像素阵列窗口中显示的像素艺术阐明了创建用户定义幻灯片的目标
***jewelsea优雅地回答了这个问题:
如何避免for循环中的Thread.sleep()中断UI线程?***这里有两个问题,您对wait()
的理解以及GUI多线程问题
关于GUI多线程。。。您将在此处找到有关平台的更多信息。稍后运行(…)
:
现在关于等待
。。。它将暂停您的线程,直到通过其监视器接收到Notify
事件。要能够调用notify(),您需要在同一对象(监视器)上进行同步
如果要使用等待
,则需要另一个线程(一个计时器
?)来唤醒/通知您<代码>睡眠
在您的情况下应该可以正常工作,只要您使用平台。runlater(…)
您在这里有两个问题,您对等待()
的理解和GUI多线程问题
关于GUI多线程。。。您将在此处找到有关平台的更多信息。稍后运行(…)
:
现在关于等待
。。。它将暂停您的线程,直到通过其监视器接收到Notify
事件。要能够调用notify(),您需要在同一对象(监视器)上进行同步
如果要使用等待
,则需要另一个线程(一个计时器
?)来唤醒/通知您<代码>睡眠
在您的情况下应该可以很好地工作,只要您使用平台。runlater(…)
的可能副本的可能副本对于这样的事情,不需要使用这些低级构造(特别是对于初学者来说,很难正确使用)。只需使用JavaFXAPI中提供的类。这个问题本质上是正确的,但是对于初学者来说,理解什么是UI线程是很重要的。我认为@sgroen没有,也许吧。但是,您只需要在创建自己的线程时才真正需要它,而OP还没有达到那种专业水平(例如,仍然难以理解何时适合使用静态
)。我提供了关于FX应用程序线程的另一种解释,我认为这种解释更完整(尽管您的观点可能会有所不同)。jewelsea在中优雅地回答了这个问题:如何避免for循环中的Thread.sleep()中断UI线程?没有必要使用这些低级构造(特别是对于初学者来说,这是很难做到的)对于类似的事情。只需使用JavaFXAPI中提供的类。这个问题基本上是正确的,但对于初学者来说,理解什么是UI线程是很重要的。我不认为@sgroen做过。也许吧。但你只需要在创建自己的线程时才真正需要它,而OP还没有达到那种专业水平(例如,仍在努力理解何时使用静态
)我提供了另一个关于FX应用程序线程的解释,我认为这个解释更完整(尽管你的观点当然可能不同)。这个问题得到了优雅的回答
final int finalR = r;
final int finalC = c;
Platform.runLater(() -> pixelArray[finalR][finalC].setFill(color));
if (selectedFiles != null) {
File playFile = selectedFiles.get(0);
openFile(playFile.getPath());
System.out.println("\n File 1 = " + playFile.getPath());
}
if (selectedFiles != null) {
File playFile = selectedFiles.get(0);
openFile(playFile.getPath());
System.out.println("\n File 1 = " + playFile.getPath());
sleep(5000);
}
synchronized (someObject) {
someObject.wait();
}
/* different thread / object */
synchronized (someObject) {
someObject.notify();
}