我只是在Java中测试一些并发编程。 基本上我有一个类(Light),它是一种有限状态机,并改变它关于命令的状态。 这就是我要尝试的:灯处于ON状态,我向该类的线程发送命令以更改OFF中的状态。 但是我在执行过程中遇到了问题。
首先,让我介绍一下课程:
enum State {ON, OFF};
public class Light implements Runnable {
private boolean cmdOn;
private boolean cmdOff;
State state;
public Light() {
cmdOn = false;
cmdOff = false;
state = State.ON;
}
@Override
public void run() {
while(true) {
switch(state) {
case ON:
if(cmdOff) {
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
state = State.OFF;
}
break;
case OFF:
if(cmdOn) {
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
state = State.ON;
}
break;
}
}
}
public void setCmdOn(boolean cmdOn) {
this.cmdOn = cmdOn;
}
public void setCmdOff(boolean cmdOff) {
this.cmdOff = cmdOff;
}
public State getState() {
return state;
}
}
And my main class:
public class Main {
public static void main(String args[]) throws InterruptedException {
Light light = new Light();
Thread t = new Thread(light);
t.start();
printState(light, 500, 1);
light.setCmdOff(true);
printState(light, 500, 4);
}
public static void printState(Light l, int time, int number) throws InterruptedException {
for(int i= 0; i < number; i++) {
System.out.println(l.getState());
Thread.currentThread().sleep(time);
}
}
输出告诉我,当我处于OFF状态时,我处于ON状态。
在第二次运行中,在if语句之上放置一条指令(System.out.println
或其他......),验证cmdOff
为真,它就会神奇地起作用。
我不明白为什么cmdOff
变量在第一次运行时没有传递给true!
为什么在第二轮运行它?
我想念一些东西,可能是同步块。但我找不到解决这个问题的解释。
感谢。
致以最诚挚的问候,
答案 0 :(得分:1)
您应该阅读同步。如果没有同步,您可能会遇到可见性错误,其中一个线程无法看到另一个线程对线程之间共享的变量所做的更改。
教程:http://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
您可以使用 synchronized块,它使用两个线程都知道要执行锁定的对象。如果两个线程在读取或更新共享数据时始终在该已知对象上同步,那么可见性和原子性永远不会成为问题。
请阅读此处以完全理解&#34;已同步&#34;:http://tutorials.jenkov.com/java-concurrency/synchronized.html 您还应该能够将共享变量声明为 volatile 。这意味着对它的所有写入和读取都会创建与其他线程的先发生关系,这就是您想要的。阅读上面的教程,以完全理解问题和术语。
请阅读此处以完全理解&#34; volatile&#34;:http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html。
答案 1 :(得分:1)
尝试在volatile
和cmdOn
上使用cmdOff
:
private volatile boolean cmdOn;
private volatile boolean cmdOff;
Volatile variable explanation in Java docs
没有它(或同步),可能无法看到更改。
答案 2 :(得分:0)
如果没有任何同步,则无法保证正在运行的线程将看到另一个线程写入cmdOff和cmdOn的值。此外,缺少状态同步意味着另一个线程可能看不到正在运行的线程的任何更改。尝试制作cmdOn,cmdOff和state volatile。