java - Vaadin 14 - 如何确保在 SessionDestroy 之后清理与会话相关的对象
问题描述
这是我在 Vaadin 14.1.18 SpringBoot 应用程序中的 MainView 类。
@Route
public class MainView extends VerticalLayout implements SessionDestroyListener{
Logger logger = LoggerFactory.getLogger(MainView.class);
public MainView() {
// To make sure of doing some Houskeeping after Session Timeout
VaadinService.getCurrent().addSessionDestroyListener(this);
String sessionId = VaadinSession.getCurrent().getSession().getId();
Zombie zombie = new Zombie(sessionId);
zombie.start();
add(new Span("Hey There! I'm at your disposal!!"));
}
@Override
public void sessionDestroy(SessionDestroyEvent sessionDestroyEvent) {
logger.warn("Just received a SessionDestroy Event with SessionId :: [{}]", sessionDestroyEvent.getSession().getSession().getId());
// Performing the HouseKeeping stuff
}
}
我还实现了一个僵尸进程,如下所示,我在我的 MainView 类中实例化了它。
public class Zombie extends Thread {
Logger logger = LoggerFactory.getLogger(Zombie.class);
private String sessionId;
public Zombie(String sessionId) {
this.sessionId = sessionId;
}
public void run() {
while (true) {
try {
Thread.sleep(60000);
Calendar cal1 = Calendar.getInstance();
logger.info("Session [{}] :: Hey, I'm still alive at {}", sessionId, cal1.getTime());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
问题是,当相应的会话被破坏时,为什么附加到它的对象仍然存在?以下日志显示,即使在 SessionDestroy 之后,僵尸进程仍在运行。我是否必须采取一些具体措施来明确清理这些对象,或者 Vaadin 应该以某种方式自动处理它?
2020-03-07 02:32:02.891 INFO 6336 --- com.mypackage.Zombie : Session [B2CBB897208717EAE264C739E2D565BE] :: Hey, I'm still alive at Sat Mar 07 02:32:02 IRST 2020
2020-03-07 02:32:56.580 WARN 6336 --- com.mypackage.MainView : Just received a SessionDestroy Event with SessionId :: [B2CBB897208717EAE264C739E2D565BE]
2020-03-07 02:33:02.891 INFO 6336 --- com.mypackage.Zombie : Session [B2CBB897208717EAE264C739E2D565BE] :: Hey, I'm still alive at Sat Mar 07 02:33:02 IRST 2020
2020-03-07 02:34:02.892 INFO 6336 --- com.mypackage.Zombie : Session [B2CBB897208717EAE264C739E2D565BE] :: Hey, I'm still alive at Sat Mar 07 02:34:02 IRST 2020
解决方案
您在另一个问题中提到了垃圾收集。在大多数情况下,会话被销毁后,它会被垃圾回收。
当 Java GC 运行时,它可能会对无法通过垃圾收集根访问的所有内容进行垃圾收集。线程是一种根,只要它们在运行,就永远不会被垃圾回收。
Vaadin 不知道您对线程的意图是什么,也不知道如何安全地阻止它们。因此,您有责任阻止他们。
通常有两种方法可以停止线程,使用interrupt()
或使用您自己的标志。
您应该使用哪一个取决于您的用例。如果您的线程正在休眠或等待,中断将立即中断它(顾名思义)并InterruptedException
抛出一个。
如果您采用这种方法,请将您的更改while(true)
为while(!Thread.interrupted())
,然后简单地调用zombie.interrupt()
以停止它。如果线程当前正在休眠, catch
则将到达您的块,因此如果它是正常行为,您可能不需要记录异常。
注意:Thread.interrupted()
在它被调用后重置中断标志,所以你不应该,例如,在 catch 块中调用它。isInterrupted()
如果您想在不重置状态的情况下读取状态,则可以使用。
另一种选择是使用您自己的标志。最简单的方法是添加一个private volatile boolean stopped = false
,然后将您的更改while (true)
为while(!stopped)
.
该volatile
关键字确保该值不会缓存在 CPU 中,这可能会延迟您的线程注意到值更改所需的时间。
然后,您可以添加一个方法来停止它,例如public void stop() { this.stopped = true; }
,并在会话销毁侦听器中调用它。由于这种方法不会中断等待的线程,因此它将始终完成循环的当前迭代,包括当前处于睡眠状态时的睡眠。
推荐阅读
- python - 有没有更快的方法使用 Python 将数百万行从 Excel 移动到 SQL 数据库?
- python - 无法从 python“wasmer”导入“ImportObject”
- sql - SQL Server递归查询以显示父母的路径
- python-3.x - 为什么我的 atom 编辑器在导入包时会给出回溯?
- python - 用于点名的 Django 动态表单
- c# - 尝试上传文件并在视图中显示文件
- javascript - Current Date converted to 10 days before and 10 days after
- python - Google colab:在子进程中打印
- python - 带有带引号的可选值的 argparse “--options --for --other --cmd”
- django - Elasticsearch 文档字段类型索引自动更改