我正在尝试使用多线程模拟一个简单的恒温器。恒温器应提高温度以达到用户要求的值,即下面代码中的“最大值”值。我有两个线程,一个负责提高温度,另一个负责降低温度。但减少的条件是它应该只在气体关闭时运行。但我在实施这个概念时遇到了问题。当下面的代码运行时,第二个线程不断抛出 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 null null null ....
更新二:
我将 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());
}
}
}
};
`