java - 线程等待和唤醒

标签 java multithreading locking wait wakeup

我正在尝试使用多线程模拟一个简单的恒温器。恒温器应提高温度以达到用户请求的值,即下面代码中的“最大值”。我有两个线程,一个负责提高温度,另一个负责降低温度。但减少的条件是必须在关气时才运行。 但我在实现这个概念时遇到了问题。当下面的代码运行时,第二个线程不断抛出 null 异常!

<pre><code>`private void formWindowActivated(java.awt.event.WindowEvent evt) {                                     
systemInitial();

Thread temperatureUp = new Thread() 
{
    @Override
    public void run()
    {
    while(true)
    {
        Max = Integer.parseInt(lblDesiredTemp.getText());
        Current = Integer.parseInt(lblCurrentTemp.getText());

            try
            {
                if(Max>Current)
                {
                    lblGasStatus.setText("On");
                    lblTemperatureSensor.setText("increasing");
                    increaseTemeture();
                }
                else
                {
                    lblGasStatus.setText("Off");
                    if(Current != 0)
                        lblTemperatureSensor.setText("decreasing");
                    else
                        lblTemperatureSensor.setText("----");
                }
            }
            catch(Exception ex)
            {
                txtLog.setText(ex.getMessage() + "\n" + txtLog.getText() );
            }
    }
    }
};

Thread systemUpdater = new Thread() 
{
    @Override
    public void run()
    {
    while(true)
    {
        try
        {
            notifyGasBoiler(this);

            if(Current>0)
                decreaseTemeture();
        }
        catch(Exception ex)
        {
            txtLog.setText(ex.getMessage() + "\n" + txtLog.getText() );
        }
    }
    }
};

    temperatureUp.start();
    systemUpdater.start();

}                                    

private synchronized void notifyGasBoiler(Thread gasOff) throws InterruptedException 
{
    try
    {
        if("On".equals(lblGasStatus.getText()))
        {
            gasOff.wait();
            txtLog.setText(txtLog.getText() + "\n" + gasOff.getName() + " waits.");
        }
        else
            notifyAll();
    }
    catch (Exception ex)
    {
        txtLog.setText(ex.getMessage() + "\n" + txtLog.getText() );
    }
}`

我在这里缺少什么?

更新一:

这是我通过运行系统并请求 2 个温度得到的日志:

温度升至 1 温度升至2 无效的 无效的 无效的 ....

更新二:

我使用 printStackTrace 来处理异常,它给了我这个:

java.lang.IllegalMonitorStateException 在 java.lang.Object.wait( native 方法) 在 java.lang.Object.wait(Object.java:485) 在 sol.smarthome.GUI.notifyGasBoiler(GUI.java:300) 在 sol.smarthome.GUI.access$900(GUI.java:14) 在 sol.smarthome.GUI$5.run(GUI.java:276)

<小时/>

更新三

<pre><code>`private void btnUpActionPerformed(java.awt.event.ActionEvent evt) {                                      
    if(Max<=8)
    {
        Max++;
        String strI = String.valueOf(Max);
        lblDesiredTemp.setText(strI);
        setGasBoilerStatus();
    }
}                                     

private void btnDownActionPerformed(java.awt.event.ActionEvent evt) {                                        
    if(Max>0)
    {
        Max--;
        String strI = String.valueOf(Max);
        lblDesiredTemp.setText(strI);
        setGasBoilerStatus();
    }
}                                       

private void formWindowActivated(java.awt.event.WindowEvent evt) {                                     
systemInitial();

tempUp = new temperatureUp();
tempDown = new temperatureDown();

tempUp.start();
tempDown.start();
}                                    

private synchronized void increaseTemeture() throws InterruptedException
{
    synchronized (monitor) {
    if (!getBoilerStatus()) 
    {
        tempUp.wait();
        //return;
    }
    else
    {

    Max = Integer.parseInt(lblDesiredTemp.getText());
    Current = Integer.parseInt(lblCurrentTemp.getText());

    if(Max>Current)
    {
        lblGasStatus.setText("On");
        lblTemperatureSensor.setText("increasing");
        Thread.sleep(4000);
        Current ++;
        lblPumpStatus.setText("On");
        lblCurrentTemp.setText(String.valueOf(Current));
        txtLog.setText("Temperature increased to " + Current + "\n"+ txtLog.getText());
        if(Current>8)
            lblDanger.setVisible(true);
    }

    setGasBoilerStatus();

    if(!isGasOn)
    {
    try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            //Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
        }
        lblGasStatus.setText("Off");
        if(Current != 0)
            lblTemperatureSensor.setText("decreasing");
        else
            lblTemperatureSensor.setText("----");
    }
    }
    }

}

private synchronized void decreaseTemeture() throws InterruptedException
{
    synchronized (monitor) {
    if(getBoilerStatus())    
    {
        tempDown.wait();
        //return;
    }
    else
    {
    Thread.sleep(4000);
    if(Current == 0 )
        return;

    Current --;
    lblCurrentTemp.setText(String.valueOf(Current));
    lblDanger.setVisible(false);
    txtLog.setText("Temperature decreased to " + Current + "\n"+ txtLog.getText());
    if(Current<1)
        lblPumpStatus.setText("Off");
    else
        lblPumpStatus.setText("On");

    setGasBoilerStatus();
    }
    }
}

private void systemInitial()
{
    lblDanger.setVisible(false);
    isPilotOn.setSelected(true);
    lblGasStatus.setText("Off");
    lblPumpStatus.setText("Off");
    isDone = true;
    isGasOn = false;
    Max = Current = 0;
}

// indicates if the boiler is on (true) or off (false)
// set as volatile to stop caching
private volatile boolean isBoilerOn = false;
protected int Max, Current;
protected boolean isDone, isGasOn, isPumpOn;
private temperatureUp tempUp;
private temperatureDown tempDown;

// Used to synchronize thread access to internal state (Current and 
// isBoilerOn member variables. The monitor is private in order
// for this class to encapsulate its synchronization policy.
private final Object monitor = new Object();

// update the bolier's status to on (true) or off (false)
public void setBoilerSatus(boolean status) {
    synchronized (monitor) {
        //  block threads until boiler is switched on
            this.isBoilerOn = status;
        // (see below), this is the place to notify them...
        notifyAll();
    }
}

// returns true if the boiler is on, false otherwise
public synchronized boolean getBoilerStatus() {
    synchronized (monitor) {
        return this.isBoilerOn;           
    }
}

private void setGasBoilerStatus() {
    synchronized (monitor) {
    if(Max>Current)
        setBoilerSatus(true);
    else
        setBoilerSatus(false);
    }
}


class temperatureUp extends Thread 
{
    @Override
    public void run()
    {
    while(true)
    {
            try
            {
                increaseTemeture();                    
            }
            catch(Exception ex)
            {
                StringWriter w = new StringWriter();
                ex.printStackTrace(new PrintWriter(w));
                //txtLog.setText(w + "\n" + txtLog.getText());
            }
    }
    }
};

class temperatureDown extends Thread
{
    @Override
    public void run() 
    {
        while(true)
        {
            try
            {
                decreaseTemeture();                    
            }
            catch(Exception ex)
            {
                StringWriter w = new StringWriter();
                ex.printStackTrace(new PrintWriter(w));
                //txtLog.setText(w + "\n" + txtLog.getText());
            }
        }
    }
};
`

最佳答案

尝试创建一个类 Thermostat 来封装恒温器的状态和行为。诀窍是使用适当的同步来维护程序的不变量。您可以在下面找到基于您的需求描述的 Thermostat 类的示例实现,用于说明目的。请注意如何使用同步来保留不变量。任何方法(例如 up(int) 和 down(int) 都会影响当前温度)可以由不同的线程同时调用,而不会由于同步而出现竞争事件或相关危险。

再次强调,这仅用于说明目的:

public final class Thermostat {

    // constant for maximum allowable temperature
    public static final int MAX_TEMP = 100;

    // the thermostat's current temperature
    private int temp = 0;

    // indicates if the boiler is on (true) or off (false)
    private boolean boilerStatus = false;

    public Thermostat() {

    }

    // Used to synchronize thread access to internal state (temp and 
    // boilerStatus member variables. The monitor is private in order
    // for this class to encapsulate its synchronization policy.
    private final Object monitor = new Object();

    // update the bolier's status to on (true) or off (false)
    public void setBoilerOn(boolean status) {
        synchronized (monitor) {
            this.boilerStatus = status;
                    // if you block threads until boiler is switched on
                    // (see below), this is the place to notify them...         
        }
    }

    // returns true if the boiler is on, false otherwise
    public boolean isBoilerOn() {
        synchronized (monitor) {
            return this.boilerStatus;           
        }
    }

    // increase the thermostat's temperature by the specified units
    // provided that the boiler has been set on
    public void up(int units) {
        synchronized (monitor) {

            // don't increase the temperature if the boiler 
            // is not turned on...
            if (!isBoilerOn()) {
                            // you could alternatively wait here if your
                            // thread needs to block...
                return;
            }

            // increase the temperature 
            if ((temp + units) <= MAX_TEMP) {
                temp += units;                          
            } else {
                // TODO : handle incorect user input here...
            }
        }
    }

    // decrease the thermostat's temperature by the specified units
    // (negative values allowed)
    public void down(int units) {
        synchronized (monitor) {
            temp -= units;          
        }
    }
}

关于java - 线程等待和唤醒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11501871/

相关文章:

java - 时间片、上下文切换和线程干扰的区别

python - 使用 asyncio 在 django 中执行周期性任务

java - Json 数组上的 Mongodb 聚合(JAVA)

java - 使 Apache HttpClient 4.3 与 sslSocketFactory/HostnameVerifier 一起工作

java - 使用 ColumnGenerator 显示 Vaadin 表中的值

multithreading - Scala 流生产和处理的多线程

Java:使用 ConcurrentHashMap 作为锁管理器

jquery - PhoneGap 单按钮按下正确方式,无多点触控干扰

苹果手机锁屏

java相当于swfobject