我有一个对象进行一些计算,然后对于每次迭代,我想绘制发生的事情。当绘图正在发生时,我希望它等待。
这就是我所做的,基本上是:
synchronized public void compute()
{
other.mark(variable);
try
{
wait();
}
catch(InterruptedException e)
{
}
}
在OtherClass中,我有
synchronized public void mark(int var)
{
//change some stuff
repaint();
notify();
}
会发生什么是compute()永远等待。我认为这会起作用,因为编译器没有给出任何错误。这两个类都没有实现Runnable或者扩展Thread,所以也许这就是问题所在?我不确定,因为我认为如果这些物体不能使用这些方法我会被警告。
我认为这可能是关于程序本身逻辑的错误,但简而言之就是我所拥有的。
答案 0 :(得分:2)
您的问题表明您希望执行一些操作,以便在GUI完成时更新GUI状态或通知GUI其进度。这就是SwingWorker的目的。两个案例的链接javadoc都有一些例子。
答案 1 :(得分:1)
这根本不像您认为的那样有效。来自wait()
方法的Javadoc(强调我的):
导致当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法。
你的程序中显然没有其他线程可以唤醒睡眠compute()
方法。
要解决您的特定问题,您要么必须有两个线程,要么实现compute()
方法作为可恢复的方法,在伪Java中是这样的:
ComputeStatus status = new ComputeStatus();
do {
compute(status); // compute iteration
mark(status); // draw iteration
status.next(); // next iteration
} while (!status.isFinished());
此处ComputeStatus
保持当前的计算状态,comupte()
知道如何从该状态继续计算。无论您是在compute()
还是在主循环中更改状态,都取决于您和您正在解决的问题。
答案 2 :(得分:0)
Object.wait()和Object.notify()仅供线程使用。在您显示的代码中,方法标记(int var)在完成之前不会返回,无需等待。此外,仅在多线程程序中需要同步方法。
您的代码应为:
public void compute()
{
other.mark(variable);
}
public void mark(int var)
{
//change some stuff
repaint();
}
答案 3 :(得分:0)
由于你的程序是一个GUI程序(我通过repaint()
调用收集),它本身就是多线程的,即使你不知道它。 (如果没有,它会表现得非常糟糕。)
如果您不使用线程,则不能使用wait / notify或任何其他类型的同步,因为没有两个线程可以同步。但是,您不必在GUI程序中明确地使用Threads来最终使用Threads。
请注意,如果您使用依赖于线程但实际上不以任何方式使用线程的方法,Java编译器将不会警告您。
您遇到以下问题之一:
1)您正在使用线程而不知道它并且您正在使用两个不同的监视器对象。因此,当您调用notify()
时,它会通知监视器该对象,但不会通知您调用wait()
的第一个对象。有许多可能的解决方案。最简单的方法之一是使用JDK 5并发实用程序来执行此操作,这比内置的基本监视器等待/通知方法更好。或者,
2)您正在一个线程中运行,并且wait / notify不好。在单线程程序中等待另一个线程通知是没有意义的 - 没有其他线程可以这样做。
假设您实际上使用的是多个Thread,那么使用Java 5及更高版本解决此问题的好方法是在包含mark()
的类中使用semaphore,并简化一点:
private final Semaphore sem = new Semaphore(1);
public void mark(int var) {
sem.acquire();
//change some stuff
repaint();
sem.release();
}
waitForSemaphore() {
sem.acquire();
}
然后在compute
中,当您希望等待waitForSemaphore()
通知时,请致电mark()
。由于mark()
已经获得了信号量,因此您必须等待mark()
释放信号量,然后才能通过调用waitForSemaphore()
来获取信号。
答案 4 :(得分:0)
重绘方法注册了绘制组件的需要,但实际上并没有绘制它,但是Java会在下一次获得它时重新绘制对象。如果你想制作类似动画的东西,那么就没有目的等待重画完成。相反,我建议你使用计时器。现在你有两个计时器选项。如果你正在更新时间不必确切的东西,那么javax.swing.Timer通常就是你要找的东西。你这样使用它:
//imports (before class definition)
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
//put this code where you want to start doing calculations
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//update your calculations
model.calculate();
//tell Java to call paint at the next chance it gets
viewer.repaint();
}
};
new Timer(delay, taskPerformer).start();
在上面的代码中,模型是您要执行计算的对象,查看器是基于模型绘制的对象。
摆动计时器的时间不是很精确,这对许多事情都很好,但有时你需要更准确地安排代码。在这种情况下,您可能希望使用java.util.Timer类。你这样使用它:
//imports (before class definition)
import java.util.Timer;
import java.util.TimerTask;
//inner class that does the calculations
public class CalculateTask extends TimerTask {
public void run() {
model.calculate();
view.repaint();
}
}
//put this code where you want to start doing calculations
int delay = 0;//time before running CalculateTask.run()
int repeat = 1000; //time between each subsequent rums of CalculateTask.run()
boolean isDaemon = true;//allow java to shutdown without stopping timer
Timer timer = new Timer(isDaemon);
timer.scheduleAtFixedRate(new CalculateTask(), delay, repeat);
答案 5 :(得分:0)
wait()永远不会被释放,因为您没有在同一个对象上进行同步。您的计算方法位于不同的对象中,因此通知调用不与您的mark()方法共享同一个监视器。
等待/通知机制适用于共享监视器,也就是说,它们必须共享相同的线程锁定机制。
wait()'唤醒'的唯一方法是,如果另一个线程在同一个对象的同步块中调用notify()。
答案 6 :(得分:0)
不幸的是,wait()永远不会停止等待。 主要原因,看你是把你的notify()。 它被同一个线程调用,无法唤醒自己。
这很简单。到达wait()命令时,mark(int var)已经完成运行,因此mark(int var)中的notify()无法将其唤醒。