通过按钮

时间:2016-03-18 00:41:11

标签: java multithreading

我正在学习线程并尝试调整此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来暂停和恢复

我的runnable类集成按钮控件:

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)块后,按下标有“Run”的按钮可更改标签。但是,按暂停不会做任何事情。

奇怪的是,即使我没有按下暂停按钮,mLock.wait()之后的print语句也会输出。 运行变量是否在我看不到的地方变为假?

    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                   
}

1 个答案:

答案 0 :(得分:2)

移动以下代码块

synchronized (this) {
      while (!running) {
         wait();
      }
}

进入for循环块。

       for (int i = 0; i < numDisplay; i++) {
            try {
              synchronized (mLock) {
                while (!running) {
                  mLock.wait();
                }
              }
            } catch(InterruptedException e) {           
               //do nothing just continue
            }

            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));

<强>更新

正如克里斯所指出的,需要使用相同的参考来执行锁定。

在简历按钮中单击,将其更改为此类。

if (!running) {
    synchronized (mLock) {
        running = true;
        mLock.notify();
    }
}

mLock是一个可以从piThread或主线程访问的全局对象。

public static final Object mLock = new Object();

<强>更新

您运行/暂停按钮不起作用,因为您的if条件检查。当running为真时,执行将首先进入if并将running设置为false。现在running == false。执行仍在继续,当它即将执行第二个if时,running = false因此条件(!running)返回true,因此它进入第二个if并设置running为true并调用mLock.notify(),因此工作线程永远不会暂停。

    if (running) {
        runPauseButton.setText("Run");
        synchronized (mLock) {
           running = false;
        }

    }
    if (!running) {
        runPauseButton.setText("Pause");
        synchronized (mLock) {
            running = true;
            mLock.notify();
        }
    }

将其更改为if .. else阻止

    if (running) {
        runPauseButton.setText("Run");
        synchronized (mLock) {
           running = false;
        }
    } else {
        runPauseButton.setText("Pause");
        synchronized (mLock) {
            running = true;
            mLock.notify();
        }
    }