使用布尔变量来停止线程
我正在学习一本 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 方法中的使用是否会在某些时候引起任何麻烦?放在声明前面的“易失性”关键字是否有助于同步它?
I have a Java book I'm learning from and in one of the examples, I saw something suspicious.
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();
}
}
As it is a MIDlet app, when it's started, the startApp method is executed. To keep it simple, the startApp method itself calls destroyApp and so the program destroys, stopping the threads and notifying the destruction.
The question is, is it safe to use this 'threadsRunning' variable and would its use inside both threads and in the destroyApp method cause any trouble at some point? Would 'volatile' keyword put in front of the declaration help to synchronize it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
设置布尔值是原子的,并且在此示例中没有“读取然后修改”逻辑,因此在这种特定情况下不需要同步对变量的访问。
然而,该变量至少应该被标记为易失性的。
将变量标记为 volatile 不会同步线程对它的访问;它确保线程不会由于代码优化或值缓存而错过另一个线程对变量的更新。例如,如果没有
volatile
,run()
内部的代码可能会在开始时仅读取一次threadsRunning
值,缓存该值,然后每次在if
语句中使用这个缓存的值,而不是再次从主内存中读取变量。如果threadsRunning
值被另一个线程更改,则可能不会被拾取。一般来说,如果您在多个线程中使用一个变量,并且其访问不同步,则应该将其标记为易失性。
Setting a boolean value is atomic, and there is no "read then modify" logic in this example, so access to the variable doesn't need to be synchronised in this particular case.
However, the variable should at least be marked volatile.
Marking the variable volatile does not synchronise the threads' access to it; it makes sure that a thread doesn't miss another thread's update to the variable due to code optimisation or value caching. For example, without
volatile
, the code insiderun()
may read thethreadsRunning
value just once at the beginning, cache the value, and then use this cached value in theif
statement every time, rather than reading the variable again from main memory. If thethreadsRunning
value gets changed by another thread, it might not get picked up.In general, if you use a variable from multiple threads, and its access is not synchronised, you should mark it volatile.