为每个线程创建一个非线程安全对象并使用happens-before保证

2023-12-29

我想将 SAAJ 中的 SOAPConnectionFactory 和 MessageFactory 类与多个线程一起使用,但事实证明我不能假设它们是线程安全的。 一些相关帖子:

  • javax.xml.soap.MessageFactory的实例是线程安全的吗? https://stackoverflow.com/questions/25279280/javax-xml-soap-messagefactorys-instance-is-thread-safe
  • MessageFactory 的 jaxp 对象缓存 https://stackoverflow.com/questions/4203071/jaxp-object-caching-for-messagefactory

这是一个有趣的小证明,证明它可以是线程安全的:http://svn.apache.org/repos/asf/axis/axis2/java/core/tags/v1.5.6/modules/saaj/src/org/apache/axis2/saaj/SOAPConnectionImpl.java http://svn.apache.org/repos/asf/axis/axis2/java/core/tags/v1.5.6/modules/saaj/src/org/apache/axis2/saaj/SOAPConnectionImpl.java据说

尽管 SAAJ 规范没有明确要求线程安全,但 Sun 参考实现中的 SOAPConnection 似乎是线程安全的。

但我仍然认为这不足以证明 SAAJ 类是线程安全的。

所以我的问题是:下面的习语正确吗?我使用主线程内可能非线程安全的工厂创建了一个 SOAPConnection 和 MessageFactory 对象,然后使用 CompletionService 接口的happens-before保证将这些对象安全地发布到执行程序任务。我还使用此发生之前保证来提取结果 HashMap 对象。

基本上我只是想验证我的推理是否合理。

public static void main(String args[]) throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletionService<Map<String, String>> completionService = new ExecutorCompletionService<>(executorService);

    //submitting 100 tasks
    for (int i = 0; i < 100; i++) {
        // there is no docs on if these classes are thread-safe or not, so creating them before submitting to the
        // external thread. This seems to be safe, because we are relying on the happens-before guarantees of the
        // CompletionService.
        SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
        SOAPConnection soapConnection = soapConnectionFactory.createConnection();
        MessageFactory messageFactory = MessageFactory.newInstance();
        int number = i;// we can't just use i, because it's not effectively final within the task below
        completionService.submit(() -> {
            // using messageFactory here!
            SOAPMessage request = createSOAPRequest(messageFactory, number);
            // using soapConnection here!
            SOAPMessage soapResponse = soapConnection.call(request, "example.com");
            soapConnection.close();
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            soapResponse.writeTo(outputStream);
            // HashMap is not thread-safe on its own, but we'll use the happens-before guarantee. See f.get() below.
            Map<String, String> result = new HashMap<>();
            result.put("soapResponse", new String(outputStream.toByteArray()));
            return result;

        });
    }

    // printing the responses as they arrive
    for (int i = 0; i < 100; i++) {
        Future<Map<String, String>> f = completionService.take();
        Map<String, String> result = f.get();
        System.out.println(result.get("soapResponse"));
    }

    executorService.shutdown();
}

/**
 * Thread-safe static method
 */
private static SOAPMessage createSOAPRequest(MessageFactory messageFactory, int number) throws Exception {
    SOAPMessage soapMessage = messageFactory.createMessage();
    SOAPPart soapPart = soapMessage.getSOAPPart();

    String serverURI = "example.com";

    SOAPEnvelope envelope = soapPart.getEnvelope();
    envelope.addNamespaceDeclaration("example", serverURI);

    SOAPBody soapBody = envelope.getBody();
    SOAPElement soapBodyElem = soapBody.addChildElement("number", "example");
    soapBodyElem.addTextNode(String.valueOf(number));

    soapMessage.saveChanges();

    return soapMessage;
}

是的,您关于 CompletionService 的推理是正确的 - .submit() 确保任务 lambda 将看到完整的对象,而 .take() 确保主线程只会看到完全形成的响应。

但是,通常情况下,您不需要这样做。static工厂方法应该始终是线程安全的,因为no方法来确保它们不会在没有整个 JVM 全局知识的情况下在其他线程中使用,并且您无法真正编写在许多环境中依赖于此的代码。有时,如果一个线程尝试使用某个线程,而另一个线程正在配置它,您会看到该实现可能会出现问题,但即使这种情况也很少见。

想象一个使用 SOAPConnectionFactory 的 servlet。不可能知道同一 JVM 中是否有其他 Web 应用程序不同时使用它,因此它必须是线程安全的。

因此,实际上,如果 MessageFactory.newInstance() 和 SOAPConnectionFactory.newInstance() 不是线程安全的,那么它们就是错误的。我会毫无顾虑地在多个线程中使用它们,如果您真的担心的话,只需检查源代码。但其实他们都很好。

另一方面,静态工厂方法创建的对象(甚至其他工厂)通常不是线程安全的,并且您不应该假设它们没有这样说明的文档。即使检查源代码也是不够的,因为如果接口没有被记录为线程安全的,那么有人可以稍后向实现添加不安全状态。

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

为每个线程创建一个非线程安全对象并使用happens-before保证 的相关文章

随机推荐

  • 每次操作后关闭访问数据库还是保持打开状态以供以后操作更好

    我正在开发一个 VB NET 项目 该项目从 Access DB 文件中获取数据 我遇到的所有代码片段都会打开数据库 执行操作并为每个操作关闭它 目前 我在应用程序运行的整个过程中都打开数据库 并且仅在应用程序退出时才将其关闭 我的问题是
  • Sequelize 中的复合主键

    有人可以建议如何在同一个表中的两列上设置主键 var relation user id type DataTypes INTEGER organization id type DataTypes INTEGER 我想定义一个主键 例如 pr
  • Gatsby - 将状态属性传递给 GraphQL 查询变量/参数?

    我是 gatsby 和 graphQL 的新手 正在尝试使用此堆栈构建一个网站 该网站将显示音乐会 活动列表 我的问题是 是否可以将数据从我的应用程序状态传递到我的查询变量 在哪里连接我的状态和 graphQL 查询 这是我的代码 clas
  • 如何开始学习hadoop [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我是一名网络开发人员 我拥有 JavaScript Jquery Php HTML 等 Web 技术的经验 我了解 C 的基本概念 最
  • 由于额外读取,通过网络读取文件速度变慢

    我正在读取一个文件 我要么读取一行数据 1600 次连续读取 17 字节 要么读取一列数据 1600 次读取 17 字节 间隔为 1600 17 27 200 字节 该文件位于本地驱动器或远程驱动器上 我执行了 10 次读取操作 因此我希望
  • Sphinx Docs 不导入 Django 项目设置

    我最近刚刚将 Django 项目移至新的 virtualenv 中 该项目运行良好 但我在构建 Sphinx 文档时遇到问题 在我的 conf py 中我有这个 import sys os sys path append path to m
  • 如何使用 Ruby 逐行将 csv 转换为数组?

    输入文件如下所示 dog white male cat purple female rat gray male 我想逐行检查并处理这些数据 File open animals csv while file has next line cur
  • 对于drawable文件夹中的默认资源(MDPI大小),drawable-mdpi文件夹有什么意义?

    我有各种不同像素密度的全套图像 并且我需要将位图资源放入可绘制文件夹 位于 MDPI 中以用作默认资源 以防止在我未满足的像素密度设备上崩溃 例如xhdpi 但这意味着将drawable mdpi中的资源复制到drawable文件夹中 因此
  • 读取时链接的 GZipStream/DeflateStream 和 CryptoStream (AES) 中断

    我想压缩然后加密我的数据 为了提高速度 不必写入字节数组并返回 决定将用于压缩和加密的流链接在一起 当我写入 压缩和加密 数据时 它工作得很好 但是当我尝试读取数据 解压缩和解密 时 读取操作会中断 只需调用 Read 一次即可读取 0 个
  • 如何以其他用户身份连接到数据库?

    我目前正在为一个学校项目创建一个 API 一切都运行良好 我的设置是 Node v10 Postgres Koa 等等 我目前有这个 CREATE ROLE sa WITH LOGIN PASSWORD some password CREA
  • 如何通过 API 查询 Asana 中的存档任务

    我有兴趣从 Asana 导出数据 以便我们可以从中运行报告 为此 我需要获取所有任务的列表 包括存档的任务 我对列出任务的API的理解是 如果任务被存档 那么在获取项目的任务时将不会检索到它 有没有办法查询所有任务 无论它们是否已存档 有a
  • 绘制线性回归后预测的条件密度

    这是我的数据框 data lt structure list Y c NA 1 793 0 642 1 189 0 823 1 715 1 623 0 964 0 395 3 736 0 47 2 366 0 634 0 701 1 692
  • 神经网络标准化输出数据

    我有神经网络的训练数据以及预期输出 每个输入都是 10 维向量 有 1 个预期输出 我已经使用高斯规范化了训练数据 但我不知道如何规范化输出 因为它只有单一维度 有任何想法吗 Example 原始输入向量 128 91 71 076 100
  • Import-Module 仅在从 Get-Module 进行管道传输时才有效

    I wrote a simple PowerShell module I need to keep more versions of the module All paths to versions are added to env PSM
  • case when 语句中按列号对表进行排序

    是否可以在 case when 语句中对带有列号的表进行排序 这是代码 WITH Table1 AS Table2 AS INSERT INTO temp SELECT TOP 50 one id one sales two count o
  • 在heroku上阻止IP

    我在 heroku 的文档或谷歌上都没有找到这个 通常这是在主机文件中完成的 有谁知道如何在heroku上屏蔽IP吗 Heroku 没有可用于阻止 IP 的防火墙 因此您必须在应用程序级别阻止它 或者必须在应用程序前面放置某种代理以用于阻止
  • 替换列表中的每个第二个元素

    我得到了一个二维列表 5 80 2 57 5 97 2 78 2 56 6 62 5 34 3 54 6 5 2 58 5 61 5 16 其中我需要将每个第二个元素更改为 0 从第一个元素开始 所以它应该看起来像这样 0 80 0 57
  • NuGet install.ps1 脚本中的 $package 和 $project 参数包含什么?

    我正在为 NuGet 包编写第一个安装 PowerShell 脚本 我正在尝试从以下位置复制文件lib文件夹放入tools另一个 NuGet 包的文件夹 默认的 install ps1 脚本有四个参数 其中两个是 package proje
  • 累积 R 中每个可能组合的值

    假设我有数据test 给定的 dput 其中 list col 说items test lt structure list items list a c b c c d e f c g h ID c 1 1 1 2 2 row names
  • 为每个线程创建一个非线程安全对象并使用happens-before保证

    我想将 SAAJ 中的 SOAPConnectionFactory 和 MessageFactory 类与多个线程一起使用 但事实证明我不能假设它们是线程安全的 一些相关帖子 javax xml soap MessageFactory的实例