我有一本我正在学习的Java书,在其中一个例子中,我看到了一些可疑的东西。
public class ThreadExample extends MIDlet {
boolean threadsRunning = true; // Flag stopping the threads
ThreadTest thr1;
ThreadTest thr2;
private class ThreadTest extends Thread {
int loops;
public ThreadTest(int waitingTime) {
loops = waitTime;
}
public void run() {
for (int i = 1; i <= loops; i++) {
if (threadsRunning != true) { // here threadsRunning is tested
return;
}
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
System.out.println(e);
}
}
}
}
public ThreadExample() {
thr1 = new ThreadTest(2);
thr2 = new ThreadTest(6);
}
public void startApp() throws MIDletStateChangeException {
thr1.start();
thr2.start();
try {
Thread.sleep(4000); // we wait 4 secs before stopping the threads -
// this way one of the threads is supposed to finish by itself
} catch(InterruptedException e) {
System.out.println(e);
}
destroyApp();
}
public void destroyApp() {
threadsRunning = false;
try {
thr1.join();
thr2.join();
} catch(InterruptedException e) {
System.out.println(e);
}
notifyDestroyed();
}
}
由于它是MIDlet应用程序,因此在启动时会执行startApp方法。为了简单起见,startApp方法本身调用destroyApp,因此程序会销毁,停止线程并通知销毁。
问题是,使用这个'threadsRunning'变量是否安全,并且在两个线程和destroyApp方法中使用它会在某些时候引起任何麻烦吗?声明前面的'volatile'关键字是否有助于同步它?
答案 0 :(得分:6)
设置一个布尔值是原子的,没有&#34;读取然后修改&#34;在这个例子中的逻辑,所以在这种特殊情况下不需要同步对变量的访问。
但是,变量至少应标记为不稳定。
标记变量volatile不会同步线程&#39;获得它;它确保线程不会因为代码优化或值缓存而错过另一个线程对变量的更新。例如,如果没有volatile
,run()
内的代码可能会在开头只读取一次threadsRunning
值,缓存该值,然后在if
中使用此缓存值每次声明,而不是从主存中再次读取变量。如果threadsRunning
值被另一个线程更改,则可能无法获取它。
通常,如果您使用来自多个线程的变量,并且其访问权限未同步,则应将其标记为volatile。