将本地新对象传递给线程,线程安全吗?

10

我有一个方法(以下是示例),它创建了一个新列表,向其中添加一些内容,并将其传递给另一个线程进行操作。

这看起来是线程安全的。该列表是由创建它的方法本地创建的。该方法对列表进行操作,并在完成操作后再将其传递给另一个线程。

但是这种做法“感觉”不对,因为该列表在两个不同的线程中被访问,但却没有进行同步。

这段代码是否是可接受的线程安全代码?

class App
{
  public static void main(String[] args)
  {
    final ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(4);
    list.add(5);

    final ExecutorService es = Executors.newSingleThreadExecutor();
    es.execute(new Runnable() {
        @Override public void run()
        {
          for (Integer i : list)
            System.out.println(i);
        }});
    es.shutdown();
  }
}
2个回答

11

这是安全的,因为一个线程将数据写入列表,另一个线程从列表中读取数据,而执行器服务在提交任务时保证 happens-before 关系。

引用自文档

java.util.concurrent 及其子包中所有类的方法都扩展了这些保证,提供更高层次的同步。此外:

[...]

在将 Runnable 提交给 Executor 之前,线程中的操作 happens-before 其执行开始。对于提交给 ExecutorService 的 Callable 类型任务同样适用。


1

这是线程安全的,因为main正在创建这个线程,因为它正在构造启动底层线程的执行程序,并且因为它通过一个同步的BlockingQueue

你需要注意以下几点:

  1. 在对象构造函数中将列表传递给线程,因为JIT能够优化字段初始化在构造函数之外。

  2. 将列表传递给另一个线程时没有同步。例如,如果一个线程初始化列表,然后将其设置在本地字段上,该字段可以从另一个线程访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接