同步块是否阻止其他线程访问对象?

时间:2010-11-08 10:15:55

标签: java multithreading synchronization

如果我对同步块中的列表执行某些操作,是否会阻止其他线程在其他位置访问该列表?

List<String> myList = new ArrayList<String>();

synchronized {
  mylist.add("Hello");
}

这是否会阻止其他线程迭代myList并删除/添加值?

我正在寻找从列表中添加/删除值,但同时保护它免受其他线程/方法的迭代(因为列表中的值可能无效)

4 个答案:

答案 0 :(得分:12)

不,它没有。

synchronized块仅阻止其他线程进入块(更准确地说,它阻止其他线程进入在同一对象实例上同步的所有块 - 在这种情况下,块在this上同步)。

您需要在synchronized块中使用要保护的实例:

synchronized(myList) {
  mylist.add("Hello");
}

Java教程中对整个区域进行了很好的解释:

http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

答案 1 :(得分:2)

是,但仅当myList的所有其他访问都受同一对象上的同步块保护时。您发布的代码示例缺少您同步的对象(即,您获取互斥锁的对象)。如果您在一个实例中同步不同的对象或根本无法同步,那么其他线程可能会同时访问该列表。因此,在访问列表之前,必须确保所有线程必须在同一对象上输入同步块(例如,始终使用synchronized (myList) { ... })。实际上,已经有一个工厂方法将使用同步方法为您列出列表中的每个方法:Collections.synchronizedList

但是,您当然可以使用Collections.synchronizedList来包装列表,以便其所有方法都是单独同步的,但这并不一定意味着维护应用程序的不变量。单独将列表中的每个方法标记为已同步将确保列表的内部状态保持一致,但您的应用程序可能希望更多,在这种情况下,您将需要编写一些更复杂的同步逻辑或查看是否可以利用{ {3}}(强烈推荐)。

答案 2 :(得分:1)

这里的synchronized确保只有一个线程一次向myList添加Hello ...

更具体地说明同步wrt对象你可以使用

synchronized( myList ) //object name
{
    //other code
}

维诺德

答案 3 :(得分:0)

根据我对Java中并发控制的有限理解,我会说上面的代码不太可能呈现你正在寻找的行为。

synchronized块将使用您正在调用所述代码的任何对象的锁定,这将不会阻止任何其他代码访问该列表,除非所述其他代码也使用相同的锁定对象进行同步。

我不知道这是否有用,或者是否以任何方式建议,但我认为:

List myList = new ArrayList();

synchronized(myList) { mylist.add("Hello"); }

通过同步列表本身的锁定对象来提供您描述的行为。

但是,Java文档建议使用这种方式获取同步列表:

List list = Collections.synchronizedList(new ArrayList(...));

请参阅:http://download.oracle.com/javase/1.4.2/docs/api/java/util/ArrayList.html