在这上面打电话'等待'和'通知'

时间:2013-12-11 14:43:14

标签: java multithreading

我在SO上遇到了关于java多线程的几乎所有问题,但我不太明白我的理解是否正确。

我希望了解操作顺序是否如下所述。

import javax.swing.*;
import java.awt.FlowLayout;
import java.awt.event.*;

class Runner implements Runnable{
    long count = 0;
    JLabel label;
    boolean paused = false;

    public Runner(JLabel label){
        this.label = label;
    }

    public void run(){
        while(true){
            try {
                if(paused){
                    synchronized(this){
                        wait();
                    }
                }
            } catch(InterruptedException e) {}
                count++;
                label.setText(Long.toString(count));
                if(Thread.interrupted())
                    return;
        }
    }

    synchronized void pause_counting(){
        paused = true;
    }

    synchronized void start_counting(){
        paused = false;
        notifyAll();
    }
}

public class ThreadRace extends JApplet{
    boolean running = true;
    Thread thread;

    @Override
    public void init(){
        final JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout());

        JLabel threadProgress = new JLabel("0");
        final Runner runner = new Runner(threadProgress);
        thread = new Thread(runner);
        thread.start();

        panel.add(threadProgress);

        JButton toggle = new JButton("Stop");
        toggle.addActionListener(new ActionListener() {
            @Override
            synchronized public void actionPerformed(ActionEvent e) {
                System.out.println("Running: " + running);
                if(running){
                    runner.pause_counting();
                } else {
                    runner.start_counting();    
                }
                running = !running;
            }
        });
        panel.add(toggle);

        add(panel);
    }

    public void stop(){
        thread.interrupt();
    }
}

这是如何运作的?

  1. 当我调用方法pause_counting()时,我设置为暂停为假。
  2. 在run()内部,我抓住runner块内对象synchronized(this) { ... }的锁定。
  3. 当我打电话给this.wait()时,我释放了我刚刚占有的同一个锁并进入WAITING状态。
  4. 此时,任何其他方法都可以使用runner(!)
  5. 执行任何操作
  6. 我最终打电话给start_counting()
  7. 这使线程返回到RUNNING状态,并在wait()语句之后继续。虽然它仍然位于synchronized(this)块内,但它会锁定锁
  8. 但是,一旦它离开块,它就会释放锁并继续执行
  9. 我很确定我的理解存在一些缺陷。

    帮助? :(

1 个答案:

答案 0 :(得分:2)

  

这是如何运作的?

是。所有的陈述都适用于一些调整(见下文)。

但是,您的程序中存在错误。由于该线程在paused块内而不是时正在测试synchronized,因此您需要确保pausedvolatile以提供内存同步。

volatile boolean paused = false

对于JLabel数组,这可能也是必要的。只要有线程正在更改共享变量,就需要进行内存同步。


  

当我调用方法pause_counting()时,我设置为暂停为假。

是。在此处更新paused即可,因为它采用synchronized方法。

  

在run()内部,我抓住了一个对象,在同步(this){...}块内的runner [i]。

仅当paused为真时。由于您要在paused块之外测试synchronized,因此paused需要volatile以确保线程之间的内存同步。

  

当我调用this.wait()时,我释放了我刚刚占有的同一个锁并进入WAITING状态。

右。

  

此时,任何其他方法都可以自由地使用此跑步者[i](!)

之前可以自由地执行操作,但是现在已经释放了锁,它可以在不阻塞的情况下调用synchronized方法。

  

我最终打电话给start_counting()。

右。这会调用notifyAll()

  

这使线程返回RUNNING状态,并在wait()语句之后继续。虽然它仍在同步(此)块内,但它会锁定锁

首先,它使线程进入BLOCKED状态,直到start_counting()的调用者离开该方法并释放锁。

  

但是,一旦它离开块,它就会释放锁并继续执行

右。