【问题标题】:Java thread safety in singleton scoped class methods单例范围类方法中的 Java 线程安全
【发布时间】:2012-12-19 03:25:22
【问题描述】:

所以我有一个 Singleton 类,其中有一个由多个线程调用的非静态公共方法。在非静态方法中,我有对存储过程创建的对象的本地引用,我猜这意味着“新”关键字在某处被调用。

 1 public void someMethod(SomeObjectParameter parameter) {
 2      
 3     Thing thingOne = synchornizedStoredProcedureCall(): 
 4     doSomethingWith(thingOne);
 5     doSomethingElseWith(thingOne);
 6
 7 }

目前第 3 行到第 5 行位于同步代码块中,我想将其简化为仅将存储过程调用同步。

所以...假设我们有两个线程,Thread1 和 Thread2。 Thread1 即将执行第 3 行,Thread2 即将执行第 4 行。既然这是一个本地引用,那么每个线程会保持不同的引用还是 synchornizedStoredProcedureCall 会覆盖对 thingOne 的引用,因为 doSomethingWith 即将使用它?

如果 thingOne 被声明为 final 或者我让它不可变怎么办?

【问题讨论】:

    标签: java multithreading concurrency


    【解决方案1】:

    每个线程会维护一个不同的引用还是 synchornizedStoredProcedureCall 会覆盖对 thingOne 的引用,因为 doSomethingWith 即将使用它?

    不同的线程有不同的栈。 thingOne 存储在每个线程堆栈中,因此不能被其他线程覆盖。您还需要确保 synchornizedStoredProcedureCall() 每次都返回不同的 Thing 实例,而不是 static 或实例变量。两个线程需要在不同的Thing 实例上工作。

    只要doSomethingWith(...)doSomethingElseWith(...) 调用是线程安全的,并且只使用thingOne 参数和常量(等),保护synchornizedStoredProcedureCall() 就可以了。只是

    正如@Marko 指出的那样,没有看到Thing 类,我们不能保证它是线程安全的并且不存储内部状态。

    【讨论】:

    • 我相信 MyBatis DAO 确实会在每次调用时创建一个新对象。我在之前的线程测试中没有看到任何反指示。 Thing 实际上只是一个模型对象,没有静态字段,只有 getter/setter。
    • 因此,如果使用“new”创建的局部变量和局部对象引用是每个线程的响应,那么这似乎就是答案。在稍后的情况下,我们会从中提取日期,但在 getter 中我们会复制一份以避免泄露内部引用。好的,我还验证了“新”关键字用于生成事物,所以这些都应该不同。
    • 回应第一句。是的。我没有足够的上下文来评论下半场。
    【解决方案2】:

    答案取决于您未提供的许多细节。关于Thing 类的许多细节很重要:它可能有一些可能不是线程安全的内部共享状态(请参阅Flyweight 设计模式)。这些事实必须记录在 Javadoc 类中;否则很难从源代码中找出来。

    【讨论】:

      【解决方案3】:

      Thingone 无论如何都是线程安全的,因为它在堆栈上被声明为 threadlocal。如果 thingone 是一个没有在方法中声明的实例变量,你就会遇到问题;但事实并非如此——所以你没有。

      【讨论】:

        【解决方案4】:

        your thingOne 是局部变量。它是线程安全的。每个线程都有自己的本地副本。

        【讨论】:

          【解决方案5】:

          您需要确保thingOne 未被共享。即使它是从同步方法返回的,如果它是从 synchornizedStoredProcedureCall 返回的单例的成员,则您的实现不再是线程安全的。

          【讨论】:

          • synchornizedStoredProcedureCall 不返回单例。
          【解决方案6】:

          每个线程都会维护一个不同的引用。如果 someMethod 是静态的,情况也是如此。

          您仍然必须确保 Thing 实例本身是线程安全的。例如。 Thing 类没有静态字段,两个 Thing 实例也没有指向同一个对象的非静态字段,或者如果它们有,它们会以线程安全的方式处理它们。

          【讨论】:

            猜你喜欢
            • 2014-10-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-08
            相关资源
            最近更新 更多