我有一个方法(下面的示例),它创建一个新列表,将一些内容放入其中,并将其传递给另一个线程进行操作。
这似乎是线程安全的。该列表是创建它的方法的本地。该方法在列表上运行,并且在完成操作之前不会将其传递给另一个线程。
但是这个感觉错误,因为列表是在两个单独的线程中访问的,但它没有同步。
这是可接受的线程安全代码吗?
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();
}
}
答案 0 :(得分:10)
这是安全的,因为一个线程写入列表,然后另一个线程从列表中读取,而执行器服务保证在您提交任务时发生之前的关系。
java.util.concurrent及其子包中所有类的方法 将这些保证扩展到更高级别的同步。在 特别是:
[...]
在执行Runnable之前,线程中的操作发生在执行开始之前。同样适用于Callables 提交给ExecutorService。
答案 1 :(得分:1)
这是线程安全的,是的,因为这个main
是创建这个线程,因为它正在构建启动底层线程的执行器,因为它通过BlockingQueue
这是同步的。
您需要注意的是:
将一个列表传递给对象构造函数内的一个线程,因为JIT能够优化 构造函数的字段初始化。
将列表传递给另一个没有同步的线程。例如,如果一个线程初始化列表,然后将其设置在可从另一个线程访问的本地字段上。