我是Java和线程的新手,我在java中有以下GUI应用程序:
在一个框架中,用户点击任意位置的鼠标并显示图像。
图像出现后,实时计时器开始运行,在jLabel
中自行更新
根据用户在gui上选择的值,该计时器最长可达5秒。
同时播放声音片段。如果图像和声音匹配,用户点击并停止 计时器。更新几个jLabel值以反映匹配或未命中。 如果不是,则用户处于空闲状态,并在计时器用完后等待图像/声音剪辑对改变。 如果任一用户停止计时器或计时器用完,应用程序将等待图像间时间段的预选值并转到 下一个图像/声音值。
我有以下结构:
我打电话
while(true)
{
SwingUtilities.invokeAndWait(displayTimer);
}
在我的run()
方法中。
我的Runnable
是
private final Runnable displayTimer= new Runnable()
{
public void run()
{
displayElapsed(System.currentTimeMillis() - startTime);
}
};
稍后初始化startTime
并开始任务开始的参考点。
我的displayElapsed()
方法很麻烦,检查计时器是通过用户输入还是不活动来停止。如果不,
然后它更新负责计时器的jLabel
。
如果是,则调用startInteraction()
方法。
startInteraction()
准备新的图像和声音,分别显示和播放每一个,创建一个新的线程updater
并启动它。
我还有一个mouseListener
来监听用户输入。它会在用户点击时调用updater.interrupt()
。
现在,问题。我知道,挥杆是线程不安全的。行为中肯定存在小问题,因为有时候它不会回答用户 鼠标立即点击,有时会通过两个图像/声音对没有适当的等待量。标签也不会立即更新。
一般来说,结构看起来像一团糟,我无法在逻辑上解释。
我所知道的是我为每个displayElapsed
启动一个新线程,每次有用户或空闲停止时我都会中断它。所以从技术上讲,每个线程都应该是顺序的。
必须有一个更好的方法来做到这一点,我想看看重写这个是一个好的开始。
答案 0 :(得分:2)
查看有关SwingWorker的这篇文章。程序遇到的问题是事件调度线程(用于呈现用户界面的唯一线程)被无限循环阻塞,因为runnable在EDT中同步执行。
您想要的是在另一个线程中运行您的计时器代码,并在此线程中发布定期任务以更新EDT中的标签。 SwingWorker类将帮助您完成此任务。要做到这一点,你
doInBackground
以使您的计时循环publish
传递时间戳(或任何您想要放入标签的内容)process
更新标签run
。