同步关键字 - 它是如何工作的?

时间:2012-07-06 13:54:20

标签: java multithreading concurrency

如果我有一个类,则将其称为X,X包含一个集合(假设我没有使用其中一个同步的指令,只是一个正常的指令)。

如果我要编写自己的方法synchronized add() - 锁定如何工作?锁定是在X的实例上完成的,而不是在集合对象上完成的吗?

因此,同步我的add()方法不会阻止X的许多实例调用add()并插入到集合中 - 因此我仍然可能遇到线程问题?

4 个答案:

答案 0 :(得分:4)

synchronized方法锁定对象。如果X.add已同步,则会阻止同时执行同一X对象的其他同步方法。如果该X对象中的任何人都可以访问同一个集合,则该集合将不受保护。

如果您希望保护您的收藏集,请确保除了X的同步方法之外,世界其他地方无法访问该收藏集。此外,您的问题中有点不清楚,但请注意,同步的非静态方法会锁定对象。假设每个X实例都有自己的集合,它们就不会相互干扰。

BTW的另一个选择是锁定集合而不是X对象:

void add(Object o) {
   synchronized(myCollection) {
      myCollection.add(o);
   }
}

这将同步对锁定集合的访问,而不是X对象。使用您认为更容易和更有效的任何一种。

答案 1 :(得分:1)

在您的示例中,synchronized将确保一次只有一个线程可以在类的一个实例上调用该方法。其他方法可以访问该集合,这是不安全的。查找concurrent collections以获取有关线程安全集合实现的更多信息。

答案 2 :(得分:1)

  

如果我要编写自己的方法synchronized add() - 锁定如何工作?锁定是在X的实例上完成的,而不是在集合对象上完成的吗?

锁定是在您同步的对象上完成的 - 而不是对象中的任何字段。要使锁定起作用,所有线程必须在同一个确切对象上同步。通常情况下,private final对象最好被锁定。

    private final Collection<...> myCollection = ...
    ...
    synchronize (myCollection) {
        myCollection.add(...);
    }

虽然常见的模式是锁定您正在保护的对象,但它实际上可以是任何常量对象。你也可以这样做:

    private final Object lockObject = new Object();
    ...
    synchronize (lockObject) {
        myCollection.add(...);
    }
  

因此,同步我的add()方法不会阻止X的许多实例调用add()并插入到集合中 - 因此我仍然可能遇到线程问题?

如果您的应用程序的其他部分正在访问myCollection 不在synchronized (myCollection)块内,那么是的,您将遇到线程问题。您需要围绕所有访问进行同步,以正确保护集合并提供内存屏障。这意味着add(...)contains(...),迭代器等。

通常,如果您尝试保护集合或其他类,则将其包装在执行同步的类中是有意义的。这会隐藏锁定并保护集合免受来自缺少synchronized块的代码的意外修改。

答案 3 :(得分:0)

您是否在多个X实例中共享一个集合?然后,您需要在集合实例本身上进行同步。不要使方法本身synchronized,而是将其所有代码包装在synchronized(coll) { ... }块中。

另一方面,如果每个X都有自己的集合,那么synchronized add()就是您所需要的。这将保证没有两个线程同时在同一个实例上执行add