与虚拟对象同步而不是与此同步

时间:2012-06-30 15:36:04

标签: java multithreading synchronized

我遇到过以下几次代码

class Foo {
   private Object lock = new Object();

   public void doSomething() {
      synchronized(lock) {
         ...

我感兴趣的是为什么创建一个锁对象而不是写synchronized(this)?是否可以共享锁定?我依稀记得读到这是一个优化。真的吗?另外,在某些情况下,将锁定声明为final吗?

是否有意义

4 个答案:

答案 0 :(得分:23)

  1. 不鼓励在this上进行同步,因为如果对象本身被用作来自外部的锁,则会破坏内部同步。此外,请记住,synchronized方法也使用this作为锁定,这可能会导致不必要的影响。
  2. 建议声明锁final以防止在synchronized块内重新分配锁定对象的情况,从而导致不同的线程看到不同的锁定对象。请参阅另一个问题:Locking on a mutable object - Why is it considered a bad practice?

答案 1 :(得分:3)

想象一下,您有thread1thread2访问method1thread3thread4访问method2的情况。如果thisthread3正在访问thread4,则thread1上的同步会阻止thread2method1,这不应该thread3 thread4method1无关。对此的优化是使用两个不同的锁而不是锁定整个类实例。

这是我在JavaDoc上发现的一个很好的段落,反映了这一点:

  

同步语句对于提高并发性也很有用   细粒度的同步。例如,假设MsLunch类有   两个实例字段,c1和c2,从不一起使用。所有   必须同步这些字段的更新,但没有理由   防止c1的更新与c2的更新交错 -   这样做可以通过创建不必要的阻塞来减少并发性

答案 2 :(得分:0)

考虑使用java.util.concurrent包中的锁 例如,这可以提供更优化的锁定 - 使用ReadWriteLock将允许所有读者无需等待即可访问。

答案 3 :(得分:0)

以下是“ReentrantReadWriteLock”的完整工作示例。

 public class DataReader  {
 private static final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
 private static final Lock read = readWriteLock.readLock();
 private static final Lock write = readWriteLock.writeLock();
 public static void loadData() {
  try {
   write.lock();
   loadDataFromTheDB());
  } finally {
   write.unlock();
  }
 }

 public static boolean readData() {
  try {
   read.lock();
   readData();
  } finally {
   read.unlock();
  }
 }

 public static List loadDataFromTheDB() {
     List list = new ArrayList();
  return list;
 }

    public static void readData() throws DataServicesException {
     //Write reading logic
    }
}