2017-05-18 263 views
-2

我正在阅读java中的并发实践。有一些问题,我无法理解。 例如,java线程安全:线程安全吗?

package com.thread; 

import java.util.Collections; 
import java.util.HashSet; 
import java.util.Random; 
import java.util.Set; 

public class HiddenIterator { 
    private final Set<Integer> set = Collections.synchronizedSet(new HashSet<Integer>()); 
    public void add(Integer i) { 
     synchronized (set) { 
      set.add(i); 
     } 
    } 
    public void remove(Integer i) { 
     synchronized (set) { 
      set.remove(i); 
     } 
    } 
    public void addTenThings() { 
     Random random = new Random(); 
     for (int i = 0; i < 10; ++i) { 
      add(random.nextInt()); 
     } 
     //Hidden Iterator! 
     System.out.println("DEBUG: added ten elements to " + set); 
    } 
} 

是程序线程安全吗? 如果不是,如何编辑?

+0

我找到了[Java Concurrency Tutorial](https://docs.oracle.com/javase/tutorial/essential/concurrency/sync)。html)是一个很好的指导。 –

+0

@ D.B。不如JCIP ... – shmosel

+0

@shmosel也许不是,但总的来说,如果有人发现一个资源混乱或难以理解,读另一个资源可能是一个好主意。对一个人来说有意义的事对另一个人来说可能没有意义。 –

回答

2

您对该设置的某些访问是线程安全的:对addremove的调用是同步的,因此它们不能同时运行。

但是,在构建消息时,您的System.out行会在集合上调用toString,并且toString必须迭代该集合的元素。尽管您已经使用了synchronizedSet,它只保护对各个元素的访问 - 它不会在迭代过程中保持该集合不变。如果其他线程在您的System.out线路运行时添加和删除元素,则无法预知邮件中将显示哪些号码。您需要围绕该行的​​块来在构建消息时“冻结”该设备的内容。

请注意,只有个人add调用是同步的,所以其他线程可能会看到要添加的各个项目之间的集合。这意味着其他线程可能只会看到十个项目中的一部分。根据您的程序使用的列表,这可能会或可能不会成为问题。

如果您需要添加十个元素以原子方式添加,以便其他线程既可以全部添加也可以不添加,您可以在addTenThings方法的循环中放置​​块。

您不需要同时使用Collections.synchronizedSet​​块。其中一个是好的。区别是:

  • Collections.synchronizedSet保护所有集的访问,所以你不能忘记在需要它的地方进行同步。但是,它只能保护集合上的各个方法调用。特别是,遍历集会导致不可预知的结果,因为项可以在循环运行时由其他线程添加和删除。
  • ​​块可以保护集合上的多个方法调用,以便它们充当原子操作 - 但它们只能防止其他​​块,因此您必须记住在访问该集合的所有代码周围都使用​​。
+0

不要忘记'System.out.println'将通过'toString'迭代集合,这意味着它可能应该同步。 –

+0

哎呀,我没注意到。接得好;将编辑。 – Wyzard

+0

这个答案提出了一个重要的观点。包括官方Javadocs在内的许多地方都将同步方法称为“线程安全”,但并不总是准确。如果只存在方法同步,通常会有方法以线程不安全的方式使用该类型。 –

1

它有些太安全了,有些不够安全。您不需要明确地同步add()remove(),因为这是由synchronizedSet包装自动完成的。

但是,你需要周围的println()声明同步,因为当您连接set,它隐含在它的元素调用set.toString(),其内部迭代(“隐藏迭代器”),这是不是安全没有明确的同步,如解释在documentation