扩展 java 的 ThreadLocal 以允许在所有线程中重置值

2023-12-31

看完之后这个问题 https://stackoverflow.com/questions/2795447/is-there-no-way-to-iterate-over-or-copy-all-the-values-of-a-java-threadlocal,我想我想包装ThreadLocal来添加重置行为。

我想要有一个类似于 ThreadLocal 的东西,我可以从任何线程调用一个方法来将所有值设置回相同的值。到目前为止我有这个:

public class ThreadLocalFlag {

    private ThreadLocal<Boolean> flag;
    private List<Boolean> allValues = new ArrayList<Boolean>();

    public ThreadLocalFlag() {
        flag = new ThreadLocal<Boolean>() {
            @Override protected Boolean initialValue() {
                Boolean value = false;
                allValues.add(value);
                return value;
            }
        };
    }

    public boolean get() {
        return flag.get();
    }

    public void set(Boolean value) {
        flag.set(value);
    }

    public void setAll(Boolean value) {
        for (Boolean tlValue : allValues) {
            tlValue = value;
        }
    }
}

我担心原语的自动装箱可能意味着如果我尝试设置它们,我存储在列表中的副本将不会引用 ThreadLocal 引用的相同变量。我还没有测试过这段代码,对于像这样棘手的事情,我正在寻找一些专家的建议,然后再继续沿着这条路走下去。

有人会问“你为什么要这样做?”。我正在一个框架中工作,其中有其他线程回调到我的代码中,但我没有对它们的引用。我想定期更新他们使用的 ThreadLocal 变量中的值,因此执行该更新需要使用该变量的线程进行更新。我只需要一种方法来通知所有这些线程它们的 ThreadLocal 变量已过时。


我很高兴最近对这个三年前的问题有了新的批评,尽管我觉得它的语气有点不专业。我提供的解决方案在那段时间在生产中没有发生任何事故。然而,肯定有更好的方法来实现引发这个问题的目标,我邀请批评者提供一个明显更好的答案。为此,我将尝试更清楚地说明我试图解决的问题。

正如我之前提到的,我使用的框架中有多个线程正在使用我的代码,超出了我的控制范围。该框架是 QuickFIX/J,我正在实施应用接口 http://www.quickfixj.org/quickfixj/javadoc/1.5.3/quickfix/Application.html。该接口定义了用于处理 FIX 消息的钩子,在我的使用中,框架被配置为多线程,以便可以同时处理与应用程序的每个 FIX 连接。

但是,QuickFIX/J 框架仅为所有线程使用该接口的单个​​实现实例。我无法控制线程的启动方式,每个线程都使用不同的配置详细信息和其他状态来服务不同的连接。让某些经常访问但很少更新的状态存在于各种不同的环境中是很自然的。ThreadLocal一旦框架启动线程,就会加载它们的初始值。

在组织的其他地方,我们拥有库代码,允许我们注册回调以通知运行时更改的配置详细信息。我想注册该回调,当我收到它时,我想让所有线程知道是时候重新加载这些值了ThreadLocals,因为它们可能已经改变。该回调来自我无法控制的线程,就像 QuickFIX/J 线程一样。

我的解决方案如下使用ThreadLocalFlag(一个包裹着的ThreadLocal<AtomicBoolean>)只是为了向其他线程发出信号,表明可能是时候更新它们的值了。回调调用setAll(true),并且 QuickFIX/J 线程调用set(false)当他们开始更新时。我淡化了并发问题ArrayList因为添加列表的唯一时间是在启动期间,并且我的用例小于列表的默认大小。

我想可以使用其他线程间通信技术来完成相同的任务,但对于它正在做的事情来说,这似乎更实用。我欢迎其他解决方案。


跨线程与 ThreadLocal 中的对象交互

我首先要说的是,这是一个坏主意。ThreadLocal is a 特殊班 https://stackoverflow.com/a/15653015/113632提供速度和线程安全的优势如果使用正确的话。尝试与 a 跨线程通信ThreadLocal首先就违背了使用该类的目的。

如果您需要跨多个线程访问对象,则可以使用为此目的设计的工具,特别是线程安全集合java.util.collect.concurrent https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/package-summary.html例如ConcurrentHashMap http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html,您可以用它来复制ThreadLocal通过使用Thread对象作为键,如下所示:

ConcurrentHashMap<Thread, AtomicBoolean> map = new ConcurrentHashMap<>();

// pass map to threads, let them do work, using Thread.currentThread() as the key

// Update all known thread's flags
for(AtomicBoolean b : map.values()) {
    b.set(true);
}

更清晰,更简洁,避免使用ThreadLocal在某种程度上它根本不是设计的目的。

通知线程其数据已过时

我只需要一种方法来通知所有这些线程它们的 ThreadLocal 变量已过时。

如果您的目标只是通知其他线程某些内容已更改,则不需要ThreadLocal根本不。只需使用一个AtomicBoolean并与您的所有任务共享它,就像您共享您的任务一样ThreadLocal<AtomicBoolean>。顾名思义,更新为AtomicBoolean是原子且可见的跨线程。更好的是使用真正的同步辅助工具,例如CyclicBarrier https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CyclicBarrier.html or Phaser https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Phaser.html,但对于简单的用例来说,仅使用AtomicBoolean.

创建一个可更新的“ThreadLocal"

综上所述,如果你really想要实现一个全局可更新的ThreadLocal你的实现被破坏了。事实上,您没有遇到问题只是巧合,未来的重构很可能会引入难以诊断的错误或崩溃。那个它“工作顺利“仅意味着您的测试不完整。

  • 首先也是最重要的,一个ArrayList不是线程安全的。当多个线程可能与它交互时,您根本无法使用它(没有外部同步),即使它们会在不同的时间这样做。您现在没有看到任何问题只是巧合。
  • 将对象存储为List阻止我们删除陈旧的值。如果你打电话ThreadLocal.set()它将追加到您的列表中,而不删除以前的值,如果您预计一旦线程终止这些对象将变得无法访问,这会导致内存泄漏和潜在的意外副作用,通常是这样的情况ThreadLocal实例。您的用例巧合地避免了这个问题,但仍然不需要使用List.

这是一个实现IterableThreadLocal它安全地存储和更新所有现有的实例ThreadLocal的值,适用于您选择使用的任何类型:

import java.util.Iterator;
import java.util.concurrent.ConcurrentMap;

import com.google.common.collect.MapMaker;

/**
 * Class extends ThreadLocal to enable user to iterate over all objects
 * held by the ThreadLocal instance.  Note that this is inherently not
 * thread-safe, and violates both the contract of ThreadLocal and much
 * of the benefit of using a ThreadLocal object.  This class incurs all
 * the overhead of a ConcurrentHashMap, perhaps you would prefer to
 * simply use a ConcurrentHashMap directly instead?
 * 
 * If you do really want to use this class, be wary of its iterator.
 * While it is as threadsafe as ConcurrentHashMap's iterator, it cannot
 * guarantee that all existing objects in the ThreadLocal are available
 * to the iterator, and it cannot prevent you from doing dangerous
 * things with the returned values.  If the returned values are not
 * properly thread-safe, you will introduce issues.
 */
public class IterableThreadLocal<T> extends ThreadLocal<T>
                                    implements Iterable<T> {
    private final ConcurrentMap<Thread,T> map;

    public IterableThreadLocal() {
        map = new MapMaker().weakKeys().makeMap();
    }

    @Override
    public T get() {
        T val = super.get();
        map.putIfAbsent(Thread.currentThread(), val);
        return val;
    }

    @Override
    public void set(T value) {
        map.put(Thread.currentThread(), value);
        super.set(value);
    }

    /**
     * Note that this method fundamentally violates the contract of
     * ThreadLocal, and exposes all objects to the calling thread.
     * Use with extreme caution, and preferably only when you know
     * no other threads will be modifying / using their ThreadLocal
     * references anymore.
     */
    @Override
    public Iterator<T> iterator() {
        return map.values().iterator();
    }
}

正如您希望看到的那样,这只不过是一个包装器ConcurrentHashMap,并产生与直接使用相同的开销,但隐藏在 a 的实现中ThreadLocal,用户通常期望它是快速且线程安全的。我出于演示目的实现了它,但我真的不建议在任何设置中使用它。

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

扩展 java 的 ThreadLocal 以允许在所有线程中重置值 的相关文章

  • 我可以确定谁在调用 Java 中的函数或实例化类吗? [复制]

    这个问题在这里已经有答案了 可能的重复 在Java中 如何使用堆栈跟踪或反射找到方法的调用者 https stackoverflow com questions 421280 in java how do i find the caller
  • 使用 Maven 生成 Eclipse 项目文件

    当我尝试使用生成 Eclipse 项目文件时mvn eclipse eclipse我收到以下错误 插件管理器执行目标时出现内部错误 org apache maven plugins maven eclipse plugin 2 9 SNAP
  • Java 字符串哈希码缓存

    字符串不变性的优点之一是哈希码缓存以实现更快的访问 在这种情况下 如何处理具有相同哈希码的字符串的缓存 在这种情况下它真的能提高性能吗 在这种情况下 如何处理具有相同哈希码的字符串的缓存 被缓存的是字符串的哈希码 它被缓存在私有的int字符
  • 如何使用retrofit2动态设置超时?

    public class Router private static Retrofit retrofit null public Retrofit getRetrofit if retrofit null OkHttpClient clie
  • 通过 html tidy 提供渲染 jsp 页面

    我有一个在 Glassfish 上运行的 Java 项目 它会呈现一些难看的 HTML 这是使用各种内部和外部 JSP 库的副作用 我想设置某种渲染后过滤器 通过 HTMLTidy 提供最终的 HTML 这样源代码就很好且整洁 有助于调试
  • 如何在Spring Boot中初始化一次MongoClient并使用它的方法?

    您好 我正在尝试导出MongoClient在 Spring Boot 中成功连接后 我尝试在其他文件中使用它 这样我就不必每次需要在 MongoDB 数据库中进行更改时都调用该连接 连接非常简单 但目标是将应用程序连接到我的数据库一次 然后
  • 如何将抽象工厂与单例模式结合起来? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在用 java 编码 并且对这些模式很陌生 谁能给我一个也使用单例的工厂抽象的例子 这是一个实现类的示例单例模式 这个实现也是线程安全
  • Java Spark DataFrameReader java.lang.NegativeArraySizeException

    学习 Spark for java 并尝试阅读 csv文件为DataFrame使用DataFrameReader 甚至不能得到一个超级简单的 csv文件工作 因为我不断收到异常java lang NegativeArraySizeExcep
  • 初始堆大小无效。无法创建Java虚拟机

    我遇到了下一个问题 我尝试通过startup bat手动启动Tomcat 但似乎没有显示任何结果 然后我尝试运行shutdown bat 控制台显示如下 D apache tomcat 7 0 35 bin gt startup bat U
  • 全静态方法和应用单例模式有什么区别?

    我正在创建一个数据库来存储有关我的网站用户的信息 我正在使用 stuts2 因此使用 Java EE 技术 对于数据库 我将创建一个 DBManager 我应该在这里应用单例模式还是将其所有方法设为静态 我将使用这个 DBManager 进
  • 我需要一个字数统计程序[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我需要弄清
  • 在 Java 中创建带注释的对象时收到通知

    Intent 我有一个自定义 Java 注释 DynamicField public class RESTEndpointInvoker DynamicField key httpTimeout private long httpTimeo
  • Java 不可变对象 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在学习不变性的概念 据我了解 一旦创建对象 不可变对象就无法更改其值 但我不明白不可变对象的以下用途 They are 自动是线程
  • “___ 中的方法 ___() 是在无法访问的类或接口中定义的”编译错误

    我发现了一个奇怪的编译限制 我无法解释 并且我不明白这个限制的原因 示例1 考虑这些类 In package e1 public class C1 enum E1 A B C public E1 x In package e2 import
  • Java LRU 缓存使用 LinkedList

    堆栈溢出的新手 所以请不要介意我以菜鸟的方式问这个问题 我正在尝试使用链表实现 LRU 缓存 我在这里看到了使用 linkedHashMap 和其他数据结构的其他实现 但对于这种情况 我正在尝试使用链表创建最佳优化版本 正如我在技术期间被问
  • Java 中更高级的泛型

    假设我有以下课程 public class FixExpr Expr
  • 更新分页。是否可以?

    他们是否存在一些方法来处理更新分页 例如我有 100 行类型 Id private Integer id Column private boolean flag Column private Date last 一开始它们看起来像 id f
  • while 之后无法访问的语句[重复]

    这个问题在这里已经有答案了 我只是修改代码 在以下代码中出现错误 int x 1 System out println x x while true x System out println x x 错误在最后一行 我可以知道错误 错误 无
  • Spring Transactional 减慢了整个过程

    我正在尝试分析我有两堂课的情况 其中一个类是 ProcessImpl 它是起点并在内部调用其他子事务 我不知道出了什么问题 processImpl正在导入一些东西并将相关数据写入数据库 Specs Spring orm版本 3 2 18 发
  • 获取Java中ResultSet返回的行数

    我用过一个ResultSet返回一定数量的行 我的代码是这样的 ResultSet res getData if res next System out println No Data Found while res next code t

随机推荐

  • Powershell - 脚本在函数外部工作但不在函数内工作

    我正在尝试编写一个简单的函数 该函数从指定目录获取文件 使用一个条件过滤它们 然后将结果放回 我想出了如下 如果它没有放置在函数中 则它可以工作 而当放置在函数中时 它只运行Get ChildItem我不知道为什么 这是我的简单代码 fun
  • 如何设置 docker 注册表作为代理?

    我有一台服务器 我们将其命名为 A 它可以访问互联网 并且我可以从该服务器从官方 docker io 注册表中提取图像 我还有其他服务器 B C 出于安全原因 它们不能具有相同的访问权限 但允许访问 A 我还决定在 A 上安装一个私有注册表
  • pytorch中嵌入的加权求和

    I have a sequence of 12 words which I represent using a 12x256 matrix using word embeddings Let us refer to these as I w
  • 每天在特定时间运行 google colab

    我最近构建了一个在Google Colaboratory上运行的Python程序 我需要每天在特定时间运行该程序 那么有什么方法可以安排它在Google Colab上运行吗 你需要创建一个notebooks csv列出所有 Colabora
  • Gradle 构建无法在父级 gradle.properties 文件中找到属性

    我有多个项目 gradle 构建 我正在尝试通过外部化依赖项版本gradle properties 不幸的是 子项目无法在父项目中找到属性gradle properties 所以在父母gradle properties I have SPR
  • 在 d3 中制作响应式动画弧?

    我在d3中看这个动画 http bl ocks org mbostock 5100636 http bl ocks org mbostock 5100636 我想知道是否有任何方法可以使其响应 以便大小随着浏览器窗口大小的调整而变化 或者使
  • 使用 ng-include 导致未定义

    您好 我对 Angular 相当陌生 我刚刚开始使用它来启动我的第一个应用程序 这是我到目前为止所做的事情 这是我的索引文件 div div
  • AngularJS 中的 401 未经授权的错误处理

    我是 AngularJS 的新手 现在花了 3 天寻找处理 401 状态的方法 我尝试过拦截器 使用 http 使用 resource 但没有任何效果 我的应用程序在同一服务器上调用 JSONP 调用 当错误发生时 它会被错误回调函数捕获
  • 密码排序性能

    我正在尝试完成一项非常常见的任务 我在 Neo4J 数据库中有大量数据集 并且希望通过 RESTful Web 服务以 25 个节点的块形式返回数据 我的模型非常简单 Tenant Hash owns gt Asset Hash Name
  • 如何捕获源自reactor.stop()的Deferred中未处理的错误

    我是扭曲的新手 并且在使用以下脚本时遇到问题 当我运行以下命令时 usr bin env python from twisted internet import defer from twisted web client import ge
  • iTunes 连接截图订单

    我目前正在通过 iTunes connect 提交一个应用程序 我在一些网站上看到 您需要以与您希望的显示方式相反的顺序发布屏幕截图 但其中许多帖子都有点旧了 当我现在上传屏幕截图时 我可以拖放来更改图像顺序 第一个屏幕截图是在 App S
  • 星号表示必填字段

    我想在输入框后面放置一个 符号 我在显示时遇到问题 This problem is due to inputbox css code Here I attached my css html within php code with a sc
  • Yii2 URL Html 格式

    快速提问 我在视图脚本中使用以下代码来生成链接
  • 如何使用 capistrano 回滚到之前部署的版本?

    我尝试使用 cap rollback 但出现以下错误 美元上限回滚 任务 回滚 不存在 我需要做一些额外的设置才能使回滚正常工作吗 刚刚在这里找到了答案http github com leehambley railsless deploy
  • HTML 图像翻转 - 翻转前图像未完全加载?

    我有一个图像 在左上角作为主页链接 我使用 CSS hover 在鼠标悬停时更改图像 问题是 第一次翻转图像时需要一些时间来加载图像 有一个临时空白区域 您会看到图像逐渐加载 大约需要一秒钟 但这很烦人 我该如何解决这个问题以使翻转无缝 有
  • 如何在 C# 中向 ListView 添加列标题

    我有一个没有列的 ListView 控件 一个列表 List
  • 如何在 Android 中使用 ContentResolver 进行不区分大小写的查询?

    我的目标是在 Android Gingerbread 及以上版本上从本机数据库中获取具有特定电子邮件地址的所有行 此查询仅获取大小写也匹配的行 Cursor cursor context getContentResolver query C
  • 第一次不延迟执行setInterval函数

    有一种方法可以配置setIntervaljavascript的方法立即执行该方法 然后用定时器执行 最简单的方法是第一次直接调用该函数 foo setInterval foo delay 然而 有充分的理由避免setInterval 特别是
  • 如何使用 jQuery 从锚标记获取值?

    a href myval a 如何获取锚标记之间的值 即 这里 myval 然后将该值指定给隐藏框 我尝试用我的代码片段执行此操作 但无法弄清楚 请帮助 var a1 text a1 text
  • 扩展 java 的 ThreadLocal 以允许在所有线程中重置值

    看完之后这个问题 https stackoverflow com questions 2795447 is there no way to iterate over or copy all the values of a java thre