是否可以等待非';在Java中完成的线程数是多少?
我有一个物体可以做一些计算,然后对于每一个动作,我想画出发生了什么。画画的时候,我想让它等一等 基本上,我就是这么做的:是否可以等待非';在Java中完成的线程数是多少?,java,multithreading,concurrency,Java,Multithreading,Concurrency,我有一个物体可以做一些计算,然后对于每一个动作,我想画出发生了什么。画画的时候,我想让它等一等 基本上,我就是这么做的: synchronized public void compute() { other.mark(variable); try { wait(); } catch(InterruptedException e) { } } 在另一节课上,我有 synchronized public void mark(i
synchronized public void compute()
{
other.mark(variable);
try
{
wait();
}
catch(InterruptedException e)
{
}
}
在另一节课上,我有
synchronized public void mark(int var)
{
//change some stuff
repaint();
notify();
}
结果是compute()会永远等待。我认为这是可行的,因为编译器没有给出错误。这两个类都没有实现可运行或扩展线程,所以这可能就是问题所在?我不确定,因为我想如果这些对象不能使用这样的方法,我会被警告
我认为这可能是程序本身的逻辑错误,但简而言之,这就是我所拥有的。Object.wait()和Object.notify()只供线程使用。在您显示的代码中,方法标记(int-var)在完成之前不会返回,无需等待。此外,同步方法仅在多线程程序中需要
您的代码应该是:
public void compute()
{
other.mark(variable);
}
public void mark(int var)
{
//change some stuff
repaint();
}
这根本不像你想象的那样有效。从
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
保存当前的计算状态,并且compte()
知道如何从该状态继续计算。无论您是在compute()
还是在main循环中更改状态,都取决于您和您要解决的问题。由于您的程序是一个GUI程序(我通过repaint()
调用收集),因此它本质上是多线程的,即使您不知道它。(否则,它的表现将非常糟糕。)
如果不使用线程,则不能使用wait/notify或任何其他类型的同步,因为没有两个线程要同步。但您不必在GUI程序中显式地使用线程来结束使用线程
请注意,如果您使用依赖于线程的方法,但实际上没有以任何方式使用线程,Java编译器将不会警告您
您有以下问题之一:
1) 您正在使用线程而不知道它,并且您正在使用两个不同的监视器对象。因此,当您调用notify()
时,它会通知监视器该对象,但不会通知您调用wait()
的第一个对象。有许多可能的解决办法。最简单的方法之一是使用JDK5并发实用程序来实现这一点,它比内置的基本监视器wait/notify方法好得多。或者
2) 您正在单线程中运行,等待/通知不正常。在单线程程序中,等待另一个线程通知是没有意义的——没有其他线程可以这样做
假设您实际使用的线程不止一个,使用Java 5及更高版本解决此问题的一个好方法是在包含mark()
的类中使用一个,可能是通过,并简化一点:
private final Semaphore sem = new Semaphore(1);
public void mark(int var) {
sem.acquire();
//change some stuff
repaint();
sem.release();
}
waitForSemaphore() {
sem.acquire();
}
然后在
compute
中,当您想等待mark()
通知时,调用waitForSemaphore()
。因为mark()
已经获取了信号量,所以您必须等待mark()
释放信号量,然后compute才能通过调用waitForSemaphore()
来获取该信号量。重新绘制方法注册了绘制组件的需要,但实际上并没有绘制该组件,但是,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();
//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);
在上面的代码中,模型是要对其执行计算的对象,查看器是基于模型绘制的对象
swing计时器的计时不是很精确,这对很多事情来说都很好,但有时您需要更精确地安排代码。在这种情况下,您可能需要使用java.util.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();
//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);
您的问题表明,您希望执行一些操作,在GUI状态完成或通知GUI其进度时更新GUI状态。这就是设计的目的。这两种情况在链接的javadoc上都有一些例子。wait()永远不会被释放,因为您没有在同一个对象上同步。您的计算方法位于不同的对象中,因此notify调用与mark()方法不共享同一个监视器 等待/通知机制用于共享监视器,也就是说,它们必须共享相同的线程锁定机制 wait()将“唤醒”的唯一方法是另一个线程从同一对象的同步块中调用notify()。不幸的是wait()永远不会停止等待。 主要原因,看你把你的通知放在哪里了。 它被同一个线程调用,无法唤醒自己
这很简单。当您到达wait()命令时,mark(int-var)将已经完成运行,因此mark(int-var)中的notify()无法唤醒它。这不是真的。您不必实现线程来使用wait和notify。因为这是一个GUI程序,所以它(几乎)必须是多线程的。我没有说你需要实现线程,我的意思是你需要有线程来使用wait()和notify()。(另外,您不能实现线程,您可以扩展