我有一个守护程序线程,它在页面打开时启动。然后在关闭页面时停止该线程。所以在我持有该主题的类中,我创建它是这样的:
class A {
private static volatile boolean isStopped=false;
//this method is called then the page is loaded
public void testListener() {
Thread listener = new Thread(new Runnable() {
public void run() {
while(!isStopped) {
//perform listener event
try {
//after every event sleep for a while
Thread.sleep(1000 *2)
} catch(InterruptedException e){}
}
}
});
}
listener.setName("Test-Server-Daemon");
listener.setDaemon(true);
listener.start();
// reset back to false so thread can be restarted when the page load event,
// call this method instance
if (isStopped) {
isStopped=false;
}
}
/**This is called when page is closed**/
public static void stopListener() {
isStopped=true;
}
}
经过调查,我注意到当页面关闭并且在30秒间隔内没有再次打开时,线程正常停止。
但是当页面关闭并在2秒间隔内重新打开时,旧线程不会停止,因此会同时运行新线程。
因此,从下图中可以看到,当我关闭并快速打开页面时,我再次启动相同的线程。
有谁知道如何防止这种情况发生?
我尝试使用线程interrupt
,我重置了互斥锁但没有快乐。
编辑:
isStopped是volatile
。
答案 0 :(得分:2)
在旧线程有机会看到它应该停止之前,您可能会覆盖isStopped
与false
的值。问题出在这里:
if(isStopped)
{
isStopped=false;
}
您应该更好地隔离代码:为每个线程创建A
的单独实例,并使isStopped
实例volatile
字段(不是static
)。并删除该代码块...
答案 1 :(得分:2)
要继续@Jordão的回答,isStopped
变量应该是每个线程。我建议使用像AtomicBoolean
之类的东西,并将你的线程代码改为大约:
public AtomicBoolean testListener() {
final AtomicBoolean isStopped = new AtomicBoolean(false);
Thread listener = new Thread(new Runnable() {
public void run() {
while(!isStopped.get()) {
...
}
}
});
listener.setName("Test-Server-Daemon");
listener.setDaemon(true);
listener.start();
return isStopped;
}
然后返回页面控制器,您可以执行以下操作:
AtomicBoolean isStopped = testListener();
// do the page stuff
...
// when done stop the thread
isStopped.set(true);
答案 2 :(得分:1)
如果您的标志isStopped在至少2秒内不成立,那么当发生这种情况时,您的线程可能正在休眠。一个更简单的解决方案是避免启动/停止线程,因为这可能会导致节省的开销(这肯定会使问题复杂化)
我要做的就是一次启动线程一次。
public void run() {
try {
while(true) {
if(!isStopped) {
//perform listener event
}
//after every event sleep for a while
Thread.sleep(1000 *2);
}
} catch(InterruptedException e){}
}
通过设置标志,它会停止执行,但线程会继续检查。
答案 3 :(得分:1)
尝试使用AtomicBoolean而不是Boolean字段。 使用compareAndSet方法;如果你需要更多的澄清,请告诉我,因为javadoc非常有用。
答案 4 :(得分:0)
尝试制作isStopped volatile
,即private static volatile boolean isStopped=false;
。两个线程(主线程和您自己的线程)之间的内存同步可能存在延迟。
答案 5 :(得分:0)
将您的实例化移到方法之外并使其静态化。这个保证人你将只有一个这个线程的实例。
private static Thread listener;
完成此操作后,您可以将此添加到方法中:
if(listener.isAlive()) try { Thread.sleep(100); } catch (InterruptedException ie) {}
listener = new Thread(new Runnable() {
public void run() {
while(!isStopped) {
//perform listener event
try {
//after every event sleep for a while
Thread.sleep(1000 *2)
}
catch(InterruptedException e){}
}
}
});
现在,在前一个线程停止之前,您不会启动新线程。
(注意,不确定isAlive()是否准确,您可能需要创建自己的Thread实现以准确反映线程是否停止,如果不是)
答案 6 :(得分:0)
我会使用java.util.concurrent.ScheduledExecutorService。它将管理线程和任务的安排。
例如:
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class Scheduler {
static ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
static ScheduledFuture<?> future;
// called when the page is opened
public static void open() {
future = service.scheduleAtFixedRate(new Runnable() {
public void run() {
//perform listener event
}
}, 0, 2, TimeUnit.SECONDS); // every 2 seconds
}
// called when the page is closed
public static void close() {
// stop listener event
future.cancel(true);
future = null;
}
}