使用终结器清理弱引用缓存?

2023-12-09

假设我有一个由弱引用或软引用组成的缓存。

这些弱/软引用需要在某个时候关闭。

理想情况下,一旦 GC 从缓存中删除对象,就应该关闭这些对象。

使用终结器/清理器来关闭这些资源,同时仍然在程序末尾循环缓存并手动关闭它们是否合适?

public void CachedObject implements AutoClosable{
    private boolean open;//getter
    public CachedObject{
        //Create resource
        open=true;
    }
    @Override
    public void finalize(){
        super.finalize();
        if(open){
            try{
                close();
             }catch(IllegalStateException e){
                 //Log
            }
        }
    }
    @Override
    public void close(){
        if(open){
            //Close
            open=false;
        }else{
            throw new IllegalStateException("already closed");
        }
    }
}
private WeakHashMap<CachedObject,Object> cache=new WeakHashMap<>();

public void close(){
    //Executed when cache is not needed anymore, e.g. program termination
    for(CachedObject cachedElement:cache){
        if(cachedElement.isOpen()){
             cachedElement.close();
        }
    }
}

这是一个相当糟糕的主意finalizer, 一般来说;毕竟,它被弃用是有原因的。我认为首先重要的是要了解这种特殊方法的机制开始工作,或者为什么需要两个周期实现终结器的对象消失了。总体想法是,这是非确定性的,很容易出错,并且您可能会遇到这种方法的意外问题。

清理某些东西的事实上的方法是使用try with resources (via AutoCloseable), 一样容易 :

CachedObject cached = new CachedObject...
try(cached) {

} 

但这并不总是一个选择,就像你的情况一样,很可能是这样。我不知道你使用的是什么缓存,但我们内部使用我们自己的缓存,它实现了所谓的移除监听器(我们的实现很大程度上基于guava加上我们自己的少量补充)。那么你的缓存可能有相同的吗?如果没有,也许你可以换一个可以的?

如果两者都没有选择,则有自 java-9 以来更清晰的 API。您可以阅读它,例如执行以下操作:

static class CachedObject implements AutoCloseable {

    private final String instance;

    private static final Map<String, String> MAP = new HashMap<>();

    public CachedObject(String instance) {
        this.instance = instance;
    }

    @Override
    public void close()  {
        System.out.println("close called");
        MAP.remove(instance);
    }
}

然后尝试通过以下方式使用它:

private static final Cleaner CLEANER = Cleaner.create();

public static void main(String[] args) {

    CachedObject first = new CachedObject("first");
    CLEANER.register(first, first::close);
    first = null;
    gc();
    System.out.println("Done");

}

static void gc(){
    for(int i=0;i<3;++i){
        LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
        System.gc();
    }
}

容易,对吧?也错了。这apiNote通过以下方式提到这一点:

仅当关联对象变为幻像可达后才会调用清理操作,因此重要的是,执行清理操作的对象不保存对该对象的引用

问题是Runnable(在第二个参数中Cleaner::register) 捕获first,现在对其有强烈的引用。这意味着永远不会调用清洁操作。相反,我们可以直接遵循文档中的建议:

static class CachedObject implements AutoCloseable {

    private static final Cleaner CLEANER = Cleaner.create();
    private static final Map<String, String> MAP = new HashMap<>();
    private final InnerState innerState;
    private final Cleaner.Cleanable cleanable;

    public CachedObject(String instance) {
        innerState = new InnerState(instance);
        this.cleanable = CLEANER.register(this, innerState);
        MAP.put(instance, instance);
    }

    static class InnerState implements Runnable {

        private final String instance;

        public InnerState(String instance) {
            this.instance = instance;
        }

        @Override
        public void run() {
            System.out.println("run called");
            MAP.remove(instance);
        }
    }

    @Override
    public void close()  {
        System.out.println("close called");
        cleanable.clean();
    }
}

代码看起来有点复杂,但实际上并没有那么复杂。我们主要想做两件事:

  • 将清理代码分离到一个单独的类中
  • 并且该类必须没有对我们正在注册的对象的引用。这是通过没有参考文献来实现的InnerState to CachedObject并且还做到了static.

所以,我们可以测试一下:

 public static void main(String[] args) {

    CachedObject first = new CachedObject("first");
    first = null;
    gc();

    System.out.println("Done");
    System.out.println("Size = " + CachedObject.MAP.size());


 }

 static void gc() {
    for(int i=0;i<3;++i){
        LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
        System.gc();
    }
 }

这将输出:

run called
Done
Size = 0
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用终结器清理弱引用缓存? 的相关文章

  • Java EE:如何获取我的应用程序的 URL?

    在 Java EE 中 如何动态检索应用程序的完整 URL 例如 如果 URL 是 localhost 8080 myapplication 我想要一个可以简单地将其作为字符串或其他形式返回给我的方法 我正在运行 GlassFish 作为应
  • Play框架运行应用程序问题

    每当我尝试运行使用以下命令创建的新 Web 应用程序时 我都会收到以下错误Play http www playframework org Error occurred during initialization of VM Could no
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • INSERT..RETURNING 在 JOOQ 中不起作用

    我有一个 MariaDB 数据库 我正在尝试在表中插入一行users 它有一个生成的id我想在插入后得到它 我见过this http www jooq org doc 3 8 manual sql building sql statemen
  • Android MediaExtractor seek() 对 MP3 音频文件的准确性

    我在使用 Android 时无法在eek 上获得合理的准确度MediaExtractor 对于某些文件 例如this one http www archive org download emma solo librivox emma 01
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • 操作错误不会显示在 JSP 上

    我尝试在 Action 类中添加操作错误并将其打印在 JSP 页面上 当发生异常时 它将进入 catch 块并在控制台中打印 插入异常时出错 请联系管理员 在 catch 块中 我添加了它addActionError 我尝试在jsp页面中打
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • 如何将 pfx 文件转换为 jks,然后通过使用 wsdl 生成的类来使用它来签署传出的肥皂请求

    我正在寻找一个代码示例 该示例演示如何使用 PFX 证书通过 SSL 访问安全 Web 服务 我有证书及其密码 我首先使用下面提到的命令创建一个 KeyStore 实例 keytool importkeystore destkeystore
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • 仅将 char[] 的一部分复制到 String 中

    我有一个数组 char ch 我的问题如下 如何将 ch 2 到 ch 7 的值合并到字符串中 我想在不循环 char 数组的情况下实现这一点 有什么建议么 感谢您花时间回答我的问题 Use new String value offset
  • Java执行器服务线程池[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如果我使用 Executor 框架在
  • 如何从泛型类调用静态方法?

    我有一个包含静态创建方法的类 public class TestClass public static
  • 如何在桌面浏览器上使用 webdriver 移动网络

    我正在使用 selenium webdriver 进行 AUT 被测应用程序 的功能测试自动化 AUT 是响应式网络 我几乎完成了桌面浏览器的不同测试用例 现在 相同的测试用例也适用于移动浏览器 因为可以从移动浏览器访问 AUT 由于它是响
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • 在 Maven 依赖项中指定 jar 和 test-jar 类型

    我有一个名为 commons 的项目 其中包含运行时和测试的常见内容 在主项目中 我添加了公共资源的依赖项
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • Spring Boot @ConfigurationProperties 不从环境中检索属性

    我正在使用 Spring Boot 1 2 1 并尝试创建一个 ConfigurationProperties带有验证的bean 如下所示 package com sampleapp import java net URL import j

随机推荐

  • 如何强制单向对多关系持续存在

    当一对多关系没有逆时 核心数据就会出现问题 对相关属性所做的更改不会保留 这是我们许多人都面临的问题 因为它可以通过谷歌搜索找到 这是想问 除了明显的答案或添加反向关系之外 你们中的一些人是否找到了实现持久性的技巧 解决方法 背景 即使文档
  • CMake 找不到 Visual C++ 编译器

    安装 Visual Studio 2015 并在以前的项目上运行 CMake 后 CMake 错误指出找不到 C 编译器 The C compiler identification is unknown The CXX compiler i
  • 如何修改Eclipse IDE中的键盘快捷键?

    Title more or less says it all Specifically I ve become increasingly annoyed that in order to run an ant script I have t
  • 在哪里可以找到 Python 类?

    我在哪里可以找到类似类的文档object or dict 我想知道他们有哪些方法以及哪些属性 我找到了大部分东西http docs python org 2但我找不到类的方法和属性object 如需详细文档 请访问在线文档 pydoc服务器
  • 在 C# 插件中调用 Dynamics Web API

    我在 Microsoft Dynamics 中有一个业务流程来处理新客户端的创建 当该过程完成时 我将附加一个工作流程 该工作流程会启动一个调用插件来执行一些自定义处理的操作 我正在关注this文章来设置这个过程 在我的插件中 我调用了 D
  • Sublime Text 3 html 自动补全无法正常工作

    我正在尝试使用 sublimetext3 来编辑 html If I do ul选项卡 然后它生成 ul ul 如果我做ul temp选项卡 然后它生成 ul class temp ul 然而 当我尝试时ul gt li temp选项卡 它
  • 寻找相近浮点数之间的“离散”差异

    假设我有两个浮点数 x and y 他们的价值观非常接近 计算机上可以表示离散数量的浮点数 因此我们可以按升序枚举它们 f 1 f 2 f 3 我希望找到距离x and y在此列表中 即它们是 1 2 3 还是n离散步骤分开 是否可以仅使用
  • 如何在android中的两个选项卡之间传递值

    我已经按照 android tab host 的教程进行操作 并且能够在模拟器上运行 现在我想做的只是在一个选项卡视图中实现一个文本框和按钮 一旦用户在文本框中输入并按下按钮 文本框中输入的值就应传递到第二个选项卡 我可以使用该值进行进一步
  • Xcode 8 二进制文件未在 itunesconnect 上显示以供审核

    我已经从 Xcode 8 制作了二进制文件并通过 Application Loader 3 6 上传到 App Store 也提交成功并弹出 但是二进制文件没有在 iTunesConnect 中显示 因为它超过了 19 小时 但它没有在 i
  • 斐波那契函数的问题。 C++

    应该返回n数组的位置 但我只得到 0 而不是值 int fibonacci int n int f 100 f 0 0 f 1 1 for int i 2 i
  • 拉取 microsoft/nanoserver 容器时出现错误“Failed to OpenForBackup failed in Win32”

    尝试提取 microsoft nanoserver 映像时遇到以下错误 下载成功 提取图像期间会出现此错误 482ab31872a2 下载完成 注册层失败 重新执行错误 退出状态 1 输出 无法 OpenForBackup 在 Win32
  • 现有对象的向量

    我有一些对象 在本例中它们是向量 我希望它们存储在向量中 但不知道如何正确声明它 我的代码是 vector
  • 控制 WinForms 中的嵌套限制

    我正在运行时创建表单的控件 出于某种原因 我需要深度超过 49 个嵌套控件 即控件包含在另一个控件中 但出现以下错误 如何添加更多相互嵌套的控件 这是一段可能会重现该错误的代码 public partial class Form1 Form
  • 在 Struts2 中实现

    我目前正在处理一个项目 我的应用程序中有多个选择框 每个值应根据第一个列表中选择的先前值进行更改 这是我的代码 我没有获得第二个选择列表 这是我的jsp
  • Django FilteredSelectMultiple 未在页面上呈现

    我目前使用的是 Django 版本 1 11 2 并且想在管理页面之外使用 FilteredSelectMultiple 小部件 这是我的 forms py class TBDAuthGroupManageForm forms Form p
  • UPDATE count=count+1 是否存在并发?

    我想知道 我会遇到并发问题吗 这不在交易中 这段代码是为了Sqlite prototype 但我计划将它与 MySql 或来自 MS 的 SQL 一起使用 command CommandText UPDATE tag name SET co
  • 如何使用 Verilog 宏模拟 $display?

    我想创建一个具有多个参数的宏 就像 display 一样 我的代码看起来像这样 但它不起作用 define format macro A write s sformatf A 这就是我调用 format macro 的方式 format m
  • 如何创建自定义 UIAlertView

    我们正在创建一个沉浸式应用程序 它需要具有类似于UIAlertView 但我们不希望它看起来像一个系统对话框 我们想使用我们自己的图形 我已经完成了大部分工作 但遇到了一些障碍 如何使 UIView 显示在状态栏上方 以便我可以变暗 就像U
  • 删除“联合”非连续范围

    我不能使用rng EntireRow Delete当范围不连续时 并且范围是由 Union 构建的 我知道我可以使用排序和自动筛选根据条件删除多行 我想学习新东西 我对向后删除或使用循环不感兴趣 这太耗时了 当范围 usun 不连续时 代码
  • 使用终结器清理弱引用缓存?

    假设我有一个由弱引用或软引用组成的缓存 这些弱 软引用需要在某个时候关闭 理想情况下 一旦 GC 从缓存中删除对象 就应该关闭这些对象 使用终结器 清理器来关闭这些资源 同时仍然在程序末尾循环缓存并手动关闭它们是否合适 public voi