Java-在另一个线程中使用可变对象引用的首选设计? [英] Java - Preferred design for using a mutable object reference in another thread?

查看:162
本文介绍了Java-在另一个线程中使用可变对象引用的首选设计?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

public class ObjectA {

   private void foo() {
       MutableObject mo = new MutableObject();
       Runnable objectB = new ObjectB(mo);
       new Thread(objectB).start();
   }

}

public class ObjectB implements Runnable {

    private MutableObject mo;

    public ObjectB(MutableObject mo) {
        this.mo = mo;
    }

    public void run() {
       //read some field from mo
    }
}

从上面的代码示例中可以看到,我将可变对象传递给实现Runnable的类,该类将在另一个线程中使用该可变对象.这很危险,因为在启动新线程后,ObjectA.foo()仍然可以更改可变对象的状态.这里确保线程安全的首选方法是什么?将MutableObject传递给ObjectB时,应该复制它吗?可变对象是否应在内部确保适当的同步?我之前已经经历过很多次,尤其是在尝试在许多GUI应用程序中使用SwingWorker时.我通常会尝试确保仅将不可变的对象引用传递给将在另一个线程中使用它们的类,但这有时会很困难.

As you can see from the code sample above, I pass a mutable object to a class that implements Runnable and will use the mutable object in another thread. This is dangerous because ObjectA.foo() can still alter the mutable object's state after starting the new thread. What is the preferred way to ensure thread safety here? Should I make copy of the MutableObject when passing it to ObjectB? Should the mutable object ensure proper synchronization internally? I've come across this many times before, especially when trying to use SwingWorker in a number of GUI applications. I usually try to make sure that ONLY immutable object references are passed to a class that will use them in another thread, but sometimes this can be difficult.

推荐答案

这是一个很难回答的问题,不幸的是,答案是取决于情况".关于类的线程安全性,您有三种选择:

This is a hard question, and the answer, unfortunately, is 'it depends'. You have three choices when it comes to thread-safety of your class:

  1. 将其设为不可变,则不必担心.但这不是您要的.
  2. 使其具有线程安全性.也就是说,在类内部提供足够的并发控制,以使客户端代码不必担心并发线程会修改对象.
  3. 将其设置为非线程安全,并强制客户端代码进行某种外部同步.

您实际上是在问应该使用#2还是#3.您担心其他开发人员使用该类并且不知道它需要外部同步的情况.我喜欢将 JCIP注释 @ThreadSafe @Immutable @NotThreadSafe用作记录并发意图的方法.这并不是万无一失的,因为开发人员仍然必须阅读文档,但是如果团队中的每个人都理解这些注释并始终如一地应用它们,它将使事情变得更加清晰.

You're essentially asking whether you should use #2 or #3. You are worried about the case where another developer uses the class and doesn't know that it requires external synchronization. I like using the JCIP annotations @ThreadSafe @Immutable @NotThreadSafe as a way to document the concurrency intentions. This isn't bullet-proof, as developers still have to read the documentation, but if everyone on the team understands these annotations and consistently applies them, it does make things clearer.

例如,如果要使该类不是线程安全的,则可以使用AtomicReference使其清晰并提供同步.

For your example, if you want to make the class not thread-safe, you could use AtomicReference to make it clear and provide synchronization.

public class ObjectA {

  private void foo() {
     MutableObject mo = new MutableObject();
     Runnable objectB = new ObjectB(new AtomicReference<>( mo ) );
     new Thread(objectB).start();
  }
}

public class ObjectB implements Runnable {

  private AtomicReference<MutableObject> mo;

  public ObjectB(AtomicReference<MutableObject> mo) {
    this.mo = mo;
  }

  public void run() {
   //read some field from mo
   mo.get().readSomeField();
  }
}

这篇关于Java-在另一个线程中使用可变对象引用的首选设计?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆