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

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(使用前将#替换为@)

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

  • 最终字段可能尚未/已经初始化[重复]

    这个问题在这里已经有答案了 可能的重复 如何处理抛出检查异常的静态最终字段初始值设定项 https stackoverflow com questions 1866770 how to handle a static final field
  • Spring @Validated 在服务层

    Hej 我想使用 Validated group Foo class 在执行方法之前验证参数的注释 如下所示 public void doFoo Foo Validated groups Foo class foo 当我将此方法放入 Spr
  • 在 Java 中的 JFrame/JPanel/JComponent 中添加 Web 浏览器

    我正在开发一个 Java 应用程序 需要在应用程序中使用 Web 浏览器 我见过一些应用程序这样做 例如在同一应用程序中单击左侧面板中的提要并打开右侧面板中的链接时的 RSS 阅读器 我想实现类似的功能 在java中可以做到这一点吗 Jav
  • 如何构建和使用 TimeSeriesCollections

    我想在图表的 X 轴上显示一些日期 并且here https stackoverflow com questions 5118684 jfreechart histogram with dates据说我必须使用 TimeSeriesColl
  • JPA 的 Hibernate 查询提示

    我一直在尝试为所有可以通过设置的提示找到一个明确的资源Query setHint String Object JPA 中的方法调用 但我一无所获 有人知道一个好的参考吗 See 3 4 1 7 查询提示 http docs jboss or
  • 按名称获取 ArrayList

    这是正确的获取方式吗ArrayList
  • 默认情况下,JSF 生成不可用的 ID,这些 ID 与 Web 标准的 CSS 部分不兼容

    活跃的 JSF 或 Primefaces 用户能否解释一下为什么默认情况下会发生这种情况 为什么没有人对此采取任何措施
  • EJB 中 @Stateless 相对于 @Singleton 的真正用例是什么

    如果我正确理解EJB Singleton实际上与普通Java中的Singleton相同 也是spring中的单例 gt 一个实例 每个调用同时通过同一个实例 Stateless 声明一个 bean 它可以 但不得 具有多个实例 但限制是一个
  • Java8 项目上的 SonarQube 给出 jacoco-Exception

    我刚刚下载了最新版本 SonarQube 4 3 然后尝试使用以下命令构建 java 8 项目 mvn clean install mvn sonar sonar 这给了我下面的例外 谷歌搜索 我的印象是这是一个早期的问题 应该已经解决 h
  • 如何从 Trie 中检索给定长度的随机单词

    我有一个简单的 Trie 用来存储大约 80k 长度为 2 15 的单词 它非常适合检查字符串是否是单词 但是 现在我需要一种获取给定长度的随机单词的方法 换句话说 我需要 getRandomWord 5 来返回 5 个字母的单词 所有 5
  • Java:java.util.Preferences 失败

    我的程序将加密的产品密钥数据保存到计算机上java util Preferences类 系统首选项 而不是用户 问题是 在 Windows 和 Linux 上 尚未在 OSX 上测试过 但可能是相同的 如果我不运行该程序sudo或者具有管理
  • Java 常量枚举[重复]

    这个问题在这里已经有答案了 可能的重复 理解 Java 中的枚举 https stackoverflow com questions 1419835 understanding enums in java 为什么我们应该使用枚举而不是 Ja
  • 如何在启用嵌入时间戳和 LTV 的情况下签署 PDF?

    我正在尝试签署启用了时间戳和 LTV 的 pdf 以便它在 Adob e Reader 中显示如下 在英语中 这意味着 签名包含嵌入的时间戳 和 签名启用了 LTV 这是我正在使用的代码 PrivateKey pk get pk from
  • 应用程序中空指针异常[重复]

    这个问题在这里已经有答案了 我正在尝试在我的应用程序中实施应用程序内计费 我写了这段代码 public class Settings extends PreferenceFragment ServiceConnection mService
  • 从特定 JAR 文件读取资源(文件的重复路径)

    假设您有 jar1 和artifactId 动物园 jar2 和artifactId 动物 两个 jar 都有一个具有相同路径的资源文件 例如 animals animal txt 有什么方法可以从特定的 jar 中读取该文件吗 使用 ge
  • 测量 tomcat 的排队请求数

    因此 使用tomcat 您可以设置acceptCount值 默认为100 这意味着当所有工作线程都忙时 新连接被放置在队列中 直到队列满 之后它们被拒绝 我想要的是监视此队列中项目的大小 但无法确定是否有办法通过 JMX 获取此值 即不是队
  • Javac 版本 1.7 无法为目标 1.7 构建

    我试图在 Linux Mint 系统上使用 Sun Java JDK 1 7 0 17 编译 Java 代码 但遇到了这个问题 javac version target 1 7 javac 1 7 0 17 javac invalid ta
  • 多个对象以某种方式相互干扰[原始版本]

    我有一个神经网络 NN 当应用于单个数据集时 它可以完美地工作 但是 如果我想在一组数据上运行神经网络 然后创建一个新的神经网络实例以在不同的数据集 甚至再次同一组数据 上运行 那么新实例将产生完全错误的预测 例如 对 XOR 模式进行训练
  • 如何让JComboBox中的内容居中显示?

    目前我有这个JComboBox 我怎样才能将其中的内容居中 String strs new String 15158133110 15158133124 15158133458 JComboBox com new JComboBox str
  • Swing:创建可拖动组件...?

    我在网上搜索了可拖动 Swing 组件的示例 但我发现示例不完整或不起作用 我需要的是一个摇摆组件那可以是dragged通过鼠标 在另一个组件内 被拖拽的时候 应该已经 改变它的位置 而不仅仅是 跳 到目的地 我很欣赏无需非标准 API 即

随机推荐

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

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