本问题已经有最佳答案,请猛点这里访问。
最简单的形式,以下是设计:
class Session {
Timer t = new Timer();
// ...
};
每当分配Session时,我会在其中启动一个计时器; 计时器将在10-20分钟后过期。 现在,假设在计时器到期之前Session被销毁; 那么这是我必须停止计时器的场景。 我不知道是否有任何最后一个方法,当Session被销毁时总是被调用。
在Java中是否存在某种类似的C ++析构函数,当Session被销毁时,它可以帮助我cancel()计时器? (无需等待GC)
编辑:请不要重新加入C ++。 我想要一些相同的东西。 Session是一个电话会话,当与其连接的所有用户都断开连接时会被破坏。 现在,没有最后调用的Session方法,也没有任何异常。
不,Java中没有这样的东西。最接近的是写一个终结器,但不能保证它会运行。
会议如何被破坏?如果有一个调用的方法,请务必将代码放在那里。
你如何创建一个会话?如果您在try / catch块中执行此操作,则可以清除finally块中的所有内容。
我会编写一个close()方法来处理它并在finally块中调用它。
尝试...最后是确保调用你的整理("析构函数")代码的方法。
在Java中,变量不像C ++中那样直接表示对象 - Java中的变量是对象的引用。因此,对象不能超出范围 - 只有引用对象的变量才会超出范围。
您可以覆盖finalize(),它是类Object中的一个方法,当它将要永久丢弃一个对象时由垃圾收集器调用,但这与析构函数不完全相同。请参阅Object类中finalize()方法的API文档。
与C ++不同,您无法控制Java中的对象释放 - 也就是说,GC会在其认为合适时收集对象,只是保证它不会收集通过给定时间范围内的任何引用可以访问的任何内容。
有Object.finalize(),它作为最后机会挂钩进行清理,但运行时并不能保证它完全被调用。
我重新考虑设计,并尝试提出一种更清晰的清理计时器的方法。
大多数情况下,您可以构建问题,因此您不需要析构函数。
为每个会话创建一个计时器是相对沉重的。最好向ScheduledExecutorService提交延迟任务。通过使其重量轻,不需要取消它。 (事实上??,cancel()不会删除它,它被标记为不运行)
在这种情况下,您可以使用单个ScheduledExecutorService来实现简单化。
class Session {
private static final ScheduledExecutorService timer =
Executors.newSingleThreadScheduledExecutor();
private Future timeoutFuture = null;
// call every time you want the timeout to start from now.
public void resetTimer() {
if(timeoutFuture != null) timeoutFuture.cancel(false);
timeoutFuture = timer.schedule(new Callable() {
public Void call() {
sessionTimedOut();
return null;
}
}, TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
void sessionTimedOut() {
// what to do when the session times out.
}
}
这里是昂贵的组件,ScheduledExecutorService只创建一次并在应用程序的生命周期中存在。在清理会话(并且任务已过期)时,将丢弃Future
+1有趣,什么是ScheduledExecutorService所有关于。 你能详细说明你的答案吗?
我添加了一个例子。
首先,finalize不等于析构函数。不要试图将其作为一个整体使用;它不会起作用。 Java没有为此构建任何内容,但在某些圈子中,有一个约定使用void dispose()来实现此目的;而不是delete ptr;,你写ptr.dispose()。 (当然,内存稍后会被回收。)在这种情况下,定义finalize是个好主意,如果在调用dispose之前回收对象,则会产生某种内部错误。
您可以使用CDI(上下文依赖注入) - 例如Weld或在某些JEE服务器(TomEE,JBoss等)上运行程序。下面是一个使用数据库的示例。
在您的课程中使用适当的@ ... Scoped(ApplicationScoped,SessionScoped等)注释,例如:
@ApplicationScoped
public class MyDatabaseFactory implements Serializable {}
在使用@PostConstruct注释的某个方法中,在构造函数中执行您想要执行的操作:
@PostConstruct
private void initializeObjectsOrConnections() {
// ...
}
使用@Inject注释将对象注入其他位置(如果您愿意):
public class MyApplication {
@Inject
MyDatabaseFactory databaseFactory;
// ...
}
清理,销毁对象并断开与数据库的连接 - 您希望在使用MyPatabaseFactory类的@PreDestroy注释的方法中使用C ++从析构函数中执行的操作,例如:
@PreDestroy
private void destroyObjectsOrCloseConnections() {
// ...
}
它使用起来非常简单,我们在Java中使用了与C ++相似的析构函数。
在java中没有类似的方法。当顶级Object中定义的finalize()方法可以在垃圾收集器销毁对象时调用,但这不是您可以依赖的行为。
您可以做的最好的事情就是将对象设置为null(删除引用),这将使其为垃圾收集做好准备。