5

在 Java util logging 中,我在 init() 上启动处理程序,并在 destroy() 处关闭处理程序,它工作得非常好:创建了一个日志文件等。如果用户正常刷新页面,它仍然只创建一个日志文件。

但是,如果用户使用小程序快速刷新页面几次,似乎 destroy() 没有被调用或者可能还没有完成任务,并且由于 init() 被再次调用,它假定以前的文件仍然被锁定并创建一个新的日志文件。

我尝试同时使用 destroy() 和 finalize() 来关闭处理程序,但它不起作用。任何人都知道如何解决这个问题?

另一个小问题是:如果 init() 没有完成并且页面被刷新,实际发生了什么。它会继续这个过程并最终无法调用destroy() 还是就停在那里?

4

3 回答 3

4

引用Java 教程

Java 插件软件为每个 Java 小程序创建一个工作线程。

在多线程环境中,您应该非常小心共享资源。最好和最简单的方法是不共享任何东西(规模最好并且不会出现死锁)。

我假设,您每次都在“init”方法中初始化您的处理程序。如果是这样,您应该使用一个静态共享记录器(检查此链接)。这将有助于稍微改善情况,但如果您使用您的小程序启动多个浏览器 - 仍将创建新的日志文件。Oracle 不建议使用此解决方法,并保留此解决方法以实现向后兼容性。


推荐且易于实施的解决方案 - “每个小程序都应该有自己的记录器并写入自己的文件”。生成日志文件名的代码:

private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

private String generateFileName() {
    return String.format("applets-log/%s-%s.log", dateFormat.format(new Date()), UUID.randomUUID());
}

此外,Applet 开发的最佳实践


回答您的小问题(已更改):

根据对 java 插件中这个旧 bug的讨论,applet 可以在任何时候以一些预定义的时间间隔终止以进行清理。因此,您应该将资源清理代码放在“停止”或“销毁”方法中,但您不应该依赖该代码将执行的内容。

Applet 的生命周期由浏览器控制,当其托管文档被浏览器破坏时,不应赋予 Applet 运行的能力。

从 6u10 开始,旧插件和新插件都会在固定时间(旧插件中为 1000 毫秒,新插件中为 200 毫秒)后强制关闭小程序,以使小程序停止。

于 2012-04-14T16:08:47.663 回答
0

希望你不是在 FF 中测试。在这里阅读: https ://bugzilla.mozilla.org/show_bug.cgi?id=638070

于 2012-04-12T11:55:43.267 回答
0

您只是遇到了多线程环境的基本限制。

相对于其他线程,您真的无法判断何时destroy()finalize()将被调用。当浏览器重新加载页面时,它可能会在新线程中加载小程序。如果用户快速点击重新加载两次,它可能会创建 2 个新线程,在调用用户从未见过的线程之前和调用前一个线程init()之前调用第二个线程(用户实际看到的)。在生命周期的另一端, 可能在不再需要对象很长时间后由垃圾收集线程调用。您在多线程环境中工作,您不能指望线程之间的任何操作顺序。init()destroy()finalize()

引用 Javadoc:

小程序是一个小程序,它不打算单独运行,而是嵌入到另一个应用程序中。

如果您将只有一个日志文件,那么实际上应该由外部应用程序控制创建/打开和关闭日志。如果外部应用程序是 Web 浏览器,那么您将无法解决您遇到的问题。 再说一次,如果您在 Web 浏览器中运行小程序,则不应将日志写入文件系统。这通常是不礼貌的行为。

如果您绝对必须在 Web 浏览器中拥有 applet 的日志文件,最简单的解决方案是为每次调用init()创建一个特定于该 applet 调用的新文件。如果您想变得雄心勃勃,您可以使用锁定文件来指示正在使用的文件,并destroy()有时将未锁定的日志文件连接成一个更大的文件,但是您又遇到了跨线程协调连接过程的问题。

于 2012-04-17T02:56:56.847 回答