我已经对我的问题做了一些研究,但仍然无法解决手头的问题。线程对我来说是新的,所以我很难理解。在我的程序中,我正在启动一个在定时期间传输文件的线程。 SWT正在此程序中用于GUI。在我的主UI代码中,我有一个暂停和播放按钮。播放按钮和相关代码:
playButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if(isRunning){
// TODO implies runningThread is waiting, notify it
}else{
playButton.setEnabled(false);
pauseButton.setEnabled(true);
try {
play();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
public void play() throws IOException{
if(controller.timMan.getEventSendPreferences().equalsIgnoreCase("manual")){
isRunning = true;
manualThread.start();
}else if(controller.timMan.getEventSendPreferences().equalsIgnoreCase("timed")){
isRunning = true;
timerThread.start();
}
return;
}
timerThread实现如下:
timerThread = new Thread(new RunOnTimer(controller));
public static class RunOnTimer implements Runnable{
ScriptController controller;
public RunOnTimer(ScriptController c){
controller = c;
};
@Override
public void run(){
try{
synchronized(this){
controller.runOnTimer();
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
这里是在run:
中调用的runOnTimer()函数public void runOnTimer() throws IOException{
for(File f : dirMan.getEventFileList()){
int randomTimeValue = 0;
int range = timMan.getUpperTimerBound() - timMan.getLowerTimerBound();
if(range > 0)
randomTimeValue = (new Random().nextInt(timMan.getUpperTimerBound() - timMan.getLowerTimerBound()) + 0);
try {
Thread.sleep(1000 * (randomTimeValue + timMan.getLowerTimerBound()));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dirMan.updateFileCounts();
System.out.println("Event " + dirMan.getSentEventFiles());
File dest = new File(dirMan.getDestinationFolder() + "\\" + f.getName());
Files.copy(f.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
updateFileCounts();
return;
}
问题在线程运行时启动,但是当我调用线程在暂停的按钮监听器实现中等待时。
pauseButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if(timerThread.isAlive()){
try {
timerThread.wait();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
pauseButton.setEnabled(false);
playButton.setEnabled(true);
}
});
在我读过的其他问题以及谷歌已经显示的结果中,同步通常是这个错误的问题。与获取对象的所有者监视器有关。我再次没有使用线程,所以这个对象监视器的概念对我来说是一个谜。 因此,在阅读完这些内容之后,我尝试在RunOnTimer类的run()方法中使用synchronized,但在尝试“暂停”时似乎没有改变任何内容(即让线程等待)。
我错过了什么或做错了什么。程序将正常工作,线程将像我预期的那样运行,除了错误当然。
答案 0 :(得分:0)
如果您阅读Object.wait的文档,您将看到这条至关重要的信息:
当前主题必须拥有此对象的监视器。
这意味着你必须在你调用wait
的对象上有一个同步块。实际上,文档有一个很好的伪代码,可以正确使用wait
在你的情况下:
synchronized(timerThread)
{
while( shouldStillWait() )
{
timerThread.wait();
}
}
boolean shouldStillWait( )
{
...
}
此外,您的代码中应该有一个地方调用timerThread.notify()
,如果没有它,您将永远等待。
也就是说,自从Java 5以来,有更好的内置同步原语可以使用wait/notify
过去的事情。
这是一件好事,因为wait/notify
非常脆弱且容易出错。
我建议阅读Brian Goetz的优秀'Java Concurrency in Practice',以熟悉新的同步原语和良好的风格多线程编程。
答案 1 :(得分:0)
问题是你不能在暂停按钮的监听器中调用navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .Plain,
target: nil, action: nil)
,因为整个方法体在应用程序的事件处理线程中运行,因此该方法不拥有{{1的对象监视器}}
因此,为了实现所需的功能,你应该有一个变量来维护应用程序的状态(即它是否被暂停)。
在主应用程序类中,您可以声明timerThread.wait()
变量
timerThread
在暂停按钮事件处理方法中,您应该删除
boolean
并将其替换为
private boolean paused;
然后在 if(timerThread.isAlive()){
try {
timerThread.wait();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
中,它将是
paused = !paused; // to just toggle the state
timerThread.notifyAll(); // to notify waiting thread