2017-06-13 54 views
2

FileManager暴露了一个write方法,其中包含一个synchronized块,以防止并发问题:包含同步块的实例是否需要单例?

class FileManager{ 
    Object lock = new Object(); 

    public void write() { 
     synchronized (lock) { 
      String id = nextId(); 
      write(id); 
     } 
    } 
} 

但是,如果存在的FileManager多个实例,它们的写入方法仍然可以并发执行。将FileManager设置为单例可以很好地解决这个可能的并发问题吗?或者我应该以另一种方式使用syncrhonized关键字?

+2

如果你不想两个'FileManager'实例能够运行'write'同时,你可以让它成为一个单身人士。或者你可以让'lock'字段静态。然后你的'FileManager's将在同一个对象上同步。 – khelwood

+0

任何关于哪个更可取的建议? – ab11

回答

2

有几个方法可以做到这一点:

  • 使它成为一个单身,你也暗示,但是这是去(我不会在所有推荐的)的至少期望的方式,因为为了同步而让单独的单身人士过度杀人,而且现在沮丧的是辛格尔顿。
  • 使您锁定对象为静态,即static Object lock = new Object();,这样您将始终锁定类级锁定对象。
  • 使写入方法为静态并同步,即public static synchronized void write() {,这样您再次使用类级锁对象,但区别在于此次您将使用FileManager的级别锁,而不是您的锁对象。

其他一些需要考虑的要点:

  • 无论你选择的类级锁或对象级锁定,您将直接暴露你的锁(类级锁尤其如此),这基本上意味着,某些客户端的API可以保持锁定,并且所有依赖于对象/类级别锁定的方法都将被阻止。例如,在类级别锁定的情况下,您的API的某些客户端可以执行synchronized(FileManager.class){,并且您的所有静态+同步方法必须等到该客户端释放该锁定之后,现在如果该客户端正在进行一些密集型操作,那么性能罚款。
  • 如果你使用一些成员变量来锁定这样的private static final Object lock = new Object();,那么需要注意的一点是,使它成为private,否则它仍会暴露你的锁。否则,它不会受到我上面提到的问题的困扰。但是这种方法只有其他的一点 - (1)你不能在方法级使用它,你可以通过在​​块中包含代码块来在方法内使用这个锁。 (2)如果你的API的客户想要与你正在使用这个锁的一些同步方法同步,那么他们不能。但是还有更深层次的东西,现在通常情况下这是锁定发生的方式。
  • 如果您使用的是Java的最新版本,那么可以使用像ReentrantLockReadWriteLock这样的API,它为锁定提供更详细的支持。

选择哪种最适合您的要求。

在一般性评论,使用锁定​​或private static final Object lock = new Object();是锁定的老办法,用Java提供了新的并发API,你应该使用像ReentrantLockReadWriteLock的API实现您的同步机制。

+0

如果我选择3rd,它会锁定所有静态FileManager方法吗?如果我有'公共静态字符串read()'(不同步),执行同步'write'方法时将无法执行?如果是这样,这看起来像是第二种选择的轻微优势? – ab11

+0

如果你的'read()'没有被同步,那么就没有问题,但是如果你的'read()'或者其他方法是同步的并且是静态的,那么所有这样的静态和同步方法将会相互等待。只是等待我更新我的答案,提到几个相同的评论。 – hagrawal

+0

@ ab11 - 我认为锁定会限制在FileManager类中的其他'synchronized'静态方法。所以任何非'synchronized'静态方法都不会受到影响。 –

0

是否使用单例模式取决于个别FileManager实例是否具有自己的状态。如果所有实例基本上共享相同的状态,那么是的,单例模式将是一个很好的选择。如果在另一方面,他们可以有不同的状态,但你仍然需要跨实例方法同步访问,那么你可以类的静态成员的同步操作,如:

class FileManager { 
    static final Object lock = new Object(); 
    public void write() { 
     synchronized (lock) { 
      ... 
     } 
    } 
} 
0

但是,如果存在的文件管理器的多个实例,他们的写入方法仍然可以同时执行?

是的。它们可以并行运行,因为锁存在实例级别,即对象级别而不是级别级别

会使FileManager成为一个单身人士是一个很好的解决这个可能的并发问题?

使类单身,如果它有​​块是没有必要的。但是如果你真的只需要你的设计的FileManager的实例,那么你可以使用static锁来为Singleton。

我应该以另一种方式使用syncrhonized关键字吗?

您可以使用LockReentrantLock作为其他选择。

请参考下面的帖子更多细节:

What does 'synchronized' mean?

Avoid synchronized(this) in Java?

Synchronization vs Lock

+0

这似乎是在冲突hagrawal的答案和我的理解。如果'lock'是一个非静态局部变量,那么如何调用FileManager.write()的不同实例互相阻塞? – ab11

+0

从你的问题中分散注意力。现在纠正它。 –

相关问题