性能问题:在多线程环境中使用单例对象



我有一个类" a ",方法"calculate()"。类A的类型是singleton(Scope= singleton)。

public class A{ 
public void calculate(){
   //perform some calculation and update DB
 }
}
现在,我有一个创建20个线程的程序。所有线程都需要访问"calculate()"方法。我有多核系统。我想要线程的并行处理。

在上述场景中,我能获得性能吗?所有线程都可以在同一时间实例访问方法吗?

或者,因为类A是单例的,所以线程需要被阻塞等待。

我在web/Stackoverflow中发现了类似的问题。但是我得不到明确的答复。你能帮帮我吗?

像"单例需要同步"或"单例不需要同步"这样的语句恐怕过于简单化了。不能仅从您正在处理单例模式这一事实中得出结论。

对于多线程来说,真正重要的是共享的内容。如果执行计算的所有线程共享数据,那么您可能需要同步该访问。如果存在不能在线程间同时运行的关键代码段,则需要对其进行同步。

好消息是,通常不需要同步整个计算中的所有内容。您可能会从多核系统中获得显著的性能改进,尽管需要同步部分操作。

坏消息是这些东西非常复杂。对不起。一个可能的参考:

http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601/ref=sr_1_1?ie=UTF8&qid=1370838949&sr=8-1&keywords=java+concurrency+in+practice

这是Singleton的基本概念。在系统(JVM)中只有一个类的实例。现在,它取决于calculate()的实现。它是一个无状态的实用程序方法吗?如果是,您可能不希望将其同步。在这种情况下,多个线程将能够在同一时间实例访问它。如果calculate()不是无状态的,即它使用实例变量(这些实例变量将被多个线程使用),那么要小心;您必须使calculate()线程安全。你必须同步这个方法。至少你必须在方法内部使用一个同步块。但是,一旦这样做了,在任何时间点,只有一个线程能够访问它(同步块或方法内部的同步块)。

public void calculate() {
    //Some code goes here which does not need require thread safety.
    synchronized(someObj) {
        //Some code goes here which requires thread safety.
    }
    //Some code goes here which does not need require thread safety.
}
如果你想使用并行处理(如果这是主要目标),那么单例不是你应该使用的设计模式。
我在web/Stackoverflow中发现了类似的问题。但是我得不到明确的答复。

有一个很好的理由!!

单例方法是否需要同步是不可能的。

同步和需要同步是关于可以被不同线程共享的状态。

  • 如果不同的线程共享状态(即使是串行),则需要同步。

  • 如果不是,则不需要同步


你提供给我们的唯一线索,可以帮助我们给你一个是/否的答案是这个神秘的评论:

  // perform some calculation and update DB

…以及calculate()方法不接受参数的事实。

如果我们推断calculate()方法从单例本身的状态中获取输入,那么至少部分方法(或它调用的方法)必须在检索该状态时同步。但是,这并不意味着整个方法调用必须同步。calculate方法需要在共享数据上持有锁的时间比例将决定您实际可以获得多少并行性…

数据库的更新也需要某种同步。但是,这应该由JDBC连接对象和从中获得的对象来处理……提供遵守规则并且不尝试在多个线程之间共享连接。(数据库更新也会带来并发瓶颈…

这取决于你如何实现Singleton。如果你使用Synchronized关键字,他们就会等待。

像这样:

public final class Universe {
  public static Universe getInstance() {
     return fINSTANCE;
  }
  // PRIVATE //
  /**
  * Single instance created upon class loading.
  */
  private static final Universe fINSTANCE =  new Universe();
  /**
  * Private constructor prevents construction outside this class.
  */
  private Universe() {
    //..elided
  }
} 
上面的

在多线程环境下会表现得很好。或者你可以选择单例的枚举实现。

查看此链接了解各种单例实现:http://javarevisited.blogspot.in/2012/07/why-enum-singleton-are-better-in-java.html

多个线程可以同时调用compute ()

这些调用不会在JVM中排队(串行执行),除非您执行某种类型的并发控制(使方法synchronized是一种选择)。

你的对象是单例的事实可能会也可能不会影响性能,这取决于该对象的属性(如果有的话)如何在calculate()中使用。

还请记住,由于您正在"更新数据库",表或行级别的锁也可能限制并发性。

如果您担心性能,最好的办法是测试它。

最新更新