【发布时间】:2016-03-18 00:41:11
【问题描述】:
我正在学习线程并尝试适应 tutorial 和 tutorial。
但有些地方不对劲,因为线程在 for 循环的一次迭代之后没有继续,并且按钮的 actionListener 实现不起作用。
最初,我的线程是这样工作的:
private class EstiPi implements Runnable {
final int numDisplay = 5000000;
long numEstimation;
long numTouchCircle;
public volatile boolean timeToQuit = false;
private EstiPiGui gui;
double estiPi;
public EstiPi() {
}
@Override
public void run() {
System.out.println("Thread started");
while (!timeToQuit) {
for (int i = 0; i < numDisplay; i++) {
double x = Math.random();
double y = Math.random();
numEstimation++;
if (x * x + y * y < 1) {
numTouchCircle++;
}
}
System.out.println(numEstimation);
System.out.println(numTouchCircle);
estiPi = ((double) numTouchCircle / numEstimation) * 4;
estiPiLabel.setText(String.valueOf(estiPi));
}
}
}
但现在我正在尝试添加 GUI 以暂停和恢复
我的可运行类来集成按钮控制:
private class EstiPi implements Runnable {
final int numDisplay = 5000000;
long numEstimation;
long numTouchCircle;
double estiPi;
public EstiPi() {
}
@Override
public void run() {
System.out.println("Thread started");
try {
for (int i = 0; i < numDisplay; i++) {
double x = Math.random();
double y = Math.random();
numEstimation++;
if (x * x + y * y < 1) {
numTouchCircle++;
}
}
System.out.println(numEstimation);
System.out.println(numTouchCircle);
estiPi = ((double) numTouchCircle / numEstimation) * 4;
estiPiLabel.setText(String.valueOf(estiPi));
synchronized (this) {
while (!running) {
wait();
}
}
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
以这种方式执行的按钮操作:
private void runPauseButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
if (running) {
runPauseButton.setText("Run");
running = false;
} else {
runPauseButton.setText("Pause");
synchronized (piThread) {
running = true;
piThread.notify();
}
}
}
启动gui组件时启动线程:
public EstiPiGui() {
initComponents();
piRunner = new EstiPi();
piThread = new Thread(piRunner);
add(estiPiLabel);
add(estiCountLabel);
piThread.start();
}
我的按钮和标签:
private javax.swing.JLabel estiCountLabel;
private javax.swing.JLabel estiPiLabel;
private javax.swing.JButton runPauseButton;
更新 在集成 SO 用户的答案并添加一个 while (true) 块后,按下标有“运行”的按钮会更改标签。但是,按下暂停键没有任何作用。
奇怪的是,即使我没有按下暂停按钮,mLock.wait() 之后的打印语句也会输出。 正在运行的变量是否在我没有看到的地方变为假?
public void run() {
System.out.println("Thread started");
while (true) {
for (int i = 0; i < numDisplay; i++) {
try {
synchronized (mLock) {
while (!running) {
mLock.wait();
System.out.println("mLock : waiting");
System.out.println(running);
}
}
} catch (InterruptedException e) {
}
double x = Math.random();
double y = Math.random();
numEstimation++;
if (x * x + y * y < 1) {
numTouchCircle++;
}
}
System.out.println(numEstimation);
System.out.println(numTouchCircle);
estiPi = ((double) numTouchCircle / numEstimation) * 4;
estiPiLabel.setText(String.valueOf(estiPi));
}
}
按钮动作和初始化变量:
public class EstiPiGui extends javax.swing.JFrame {
static EstiPiGui myGui;
public volatile boolean running;
EstiPi piRunner;
Thread piThread;
public static final Object mLock = new Object();
/**
* Creates new form EstPiGui
*/
public EstiPiGui() {
initComponents();
piRunner = new EstiPi();
piThread = new Thread(piRunner);
add(estiPiLabel);
add(estiCountLabel);
piThread.start();
}
private void runPauseButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
if (running) {
runPauseButton.setText("Run");
synchronized (mLock) {
running = false;
}
}
if (!running) {
runPauseButton.setText("Pause");
synchronized (mLock) {
running = true;
mLock.notify();
}
}
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
myGui = new EstiPiGui();
myGui.setVisible(true);
}
});
}
private class EstiPi implements Runnable {
final int numDisplay = 5000000;
long numEstimation;
long numTouchCircle;
//public volatile boolean running;
private EstiPiGui gui;
double estiPi;
public EstiPi() {
}
@Override
public void run() {
System.out.println("Thread started");
while (true) {
for (int i = 0; i < numDisplay; i++) {
try {
synchronized (mLock) {
while (!running) {
mLock.wait();
System.out.println("mLock : waiting");
}
}
} catch (InterruptedException e) {
}
double x = Math.random();
double y = Math.random();
numEstimation++;
if (x * x + y * y < 1) {
numTouchCircle++;
}
}
System.out.println(numEstimation);
System.out.println(numTouchCircle);
estiPi = ((double) numTouchCircle / numEstimation) * 4;
estiPiLabel.setText(String.valueOf(estiPi));
estiCountLabel.setText(String.valueOf(numEstimation));
}
}
}
// Variables declaration - do not modify
private javax.swing.JLabel estiCountLabel;
private javax.swing.JLabel estiPiLabel;
private javax.swing.JButton runPauseButton;
// End of variables declaration
}
【问题讨论】:
-
为什么你的问题有两个不同版本的
EstiPi类?你用的是哪个版本? -
@Chris 第一个显示正在运行的版本,但没有集成按钮。第二个是我尝试集成一个不起作用的按钮。
-
乍一看我可以看到一些问题:(1)你在你的
Runnable类上调用wait,在你的Thread上调用notify(一个不同的对象,所以通知基本上没有效果)。 (2) 您的暂停/恢复逻辑在工作循环之外(因此除了您的线程退出之外,它实际上不会暂停任何内容)。 -
@chris 我明白你对不同对象调用等待和通知的意思。有没有办法避免这种情况?正如我所教的那样,我将可运行对象传递给了一个线程——不过我正在学习,所以愿意接受建议。
-
The print statement after mLock.wait() outputs even if I don't press the pause button。 Java 不能保证您的工作线程仅因notify()而被唤醒。所以你可能会看到它在wait()之后打印输出。这就是为什么您需要将它放在检查条件的循环中。见docs.oracle.com/javase/6/docs/api/java/lang/…
标签: java multithreading