且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Vaadin 14 - 如何确保在 SessionDestroy 之后清除与会话相关的对象

更新时间:2023-01-25 07:54:37

您在另一个问题中提到了垃圾收集.大多数情况下,会话销毁后,会被垃圾回收.

You mentioned garbage collection in another question. In most cases, after a session is destroyed, it will be garbage collected.

当 Java GC 运行时,它可能会垃圾收集所有不能通过垃圾收集根访问的东西.线程是根的一种类型,只要它们在运行,就永远不会被垃圾回收.

When the Java GC runs, it may garbage collect everything that is not accessible through a garbage collection root. Threads are one type of root, and are never garbage collected as long as they are running.

Vaadin 不知道您使用线程的意图是什么,也不知道如何安全地阻止它们.因此,您有责任阻止它们.

Vaadin can not know what your intentions with threads are, nor how to stop them safely. As such, it is your responsibility to stop them.

通常有两种方法可以停止线程,使用 interrupt() 或使用您自己的标志.

There are generally two ways to stop a thread, using interrupt() or with your own flag.

您应该使用哪一种取决于您的用例.如果您的线程正在休眠或以其他方式等待,中断将立即中断它(顾名思义)并抛出 InterruptedException.

Which one you should use depends on your use case. If your thread is sleeping, or otherwise waiting, an interrupt will interrupt it immediately (as the name implies) and an InterruptedException will be thrown.

如果您采用这种方法,请将您的 while(true) 更改为 while(!Thread.interrupted()),然后只需调用 zombie.interrupt() 停止它.如果线程当前正在休眠,则将到达您的 catch 块,因此如果它是正常行为,您可能不需要记录异常.

If you go with this approach, change your while(true) to while(!Thread.interrupted()), and simply call zombie.interrupt() to stop it. If the thread is currently sleeping, your catch block will be reached, so you might not need to log the exception if it's normal behavior.

注意:Thread.interrupted() 会在调用后重置中断标志,因此您不应例如在 catch 块中调用它.如果您想在不重置状态的情况下读取状态,可以使用 isInterrupted().

Note: Thread.interrupted() resets the interrupted flag after it's called, so you shouldn't, for example, call it in the catch block. You can use isInterrupted() if you want to read the state without resetting it.

另一种选择是使用您自己的标志.最简单的方法是添加一个 private volatile boolean stopped = false,并将你的 while (true) 更改为 while(!stopped).

The other option is to use your own flag. The simplest approach is to add a private volatile boolean stopped = false, and change your while (true) to while(!stopped).

volatile 关键字可确保值不会缓存在 CPU 中,这可能会延迟您的线程注意到值更改所需的时间.

The volatile keyword ensures the value is not cached in the CPU, which could delay the time it takes for your thread to notice the value change.

然后您可以添加一个方法来停止它,例如public void stop() { this.stopped = true;},并在会话销毁侦听器中调用它.由于这种方法不会中断正在等待的线程,因此它将始终完成循环的当前迭代,如果当前处于睡眠状态,则包括睡眠.

You can then add a method to stop it, e.g. public void stop() { this.stopped = true; }, and call that in the session destroy listener. As this approach does not interrupt a waiting thread, it will always finish the current iteration of the loop, including the sleep if it is currently sleeping.