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

时间:2013-01-24 22:40:04

标签: java multithreading concurrency thread-safety

我有一个方法(下面的示例),它创建一个新列表,将一些内容放入其中,并将其传递给另一个线程进行操作。

这似乎是线程安全的。该列表是创建它的方法的本地。该方法在列表上运行,并且在完成操作之前不会将其传递给另一个线程。

但是这个感觉错误,因为列表是在两个单独的线程中访问的,但它没有同步。

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

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 个答案:

答案 0 :(得分:10)

这是安全的,因为一个线程写入列表,然后另一个线程从列表中读取,而执行器服务保证在您提交任务时发生之前的关系。

引自the documentation

  

java.util.concurrent及其子包中所有类的方法   将这些保证扩展到更高级别的同步。在   特别是:

     

[...]

     

在执行Runnable之前,线程中的操作发生在执行开始之前。同样适用于Callables   提交给ExecutorService。

答案 1 :(得分:1)

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

您需要注意的是:

  1. 将一个列表传递给对象构造函数内的一个线程,因为JIT能够优化 构造函数的字段初始化。

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