0

マルチスレッドを使用して、単純なサーモスタットをシミュレートしようとしています。サーモスタットは、ユーザーが要求した値 (以下のコードの「最大」値) に到達するために温度を上げる必要があります。私は2つのスレッドを持っています.1つは温度を上げることを担当し、もう1つは温度を下げることを担当しています。減る条件はガス抜き時のみ。しかし、この概念の実装には問題があります。以下のコードが実行されると、2 番目のスレッドが 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() );
    }
}`

ここで何が欠けていますか?

更新I:

これは、システムを実行して取得したログで、2 つの温度を要求します。

温度が 1 に上昇 温度が 2 に上昇 null null null ....

更新 II:

例外に printStackTrace を使用したところ、次のようになりました。

java.lang.IllegalMonitorStateException at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:485) at sol.smarthome.GUI.notifyGasBoiler(GUI.java:300) at sol.smarthome.GUI.access$900(GUI.java:14) at 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());
            }
        }
    }
};
`
4

2 に答える 2

1

サーモスタットの状態と動作をカプセル化するクラス 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;          
        }
    }
}
于 2012-07-16T12:00:22.230 に答える
0

を使用してみてくださいFull class name (dot) this

例えば:

notifyGasBoiler(MyTempClass.this);
于 2012-07-16T09:56:10.337 に答える