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

时间:2013-06-10 04:20:26

标签: java spring singleton

我有一个类“A”,方法是“calculate()”。 A类的类型为singleton(Scope = Singleton)。

public class A{ 

public void calculate(){
   //perform some calculation and update DB
 }

}

现在,我有一个创建20个线程的程序。所有线程都需要访问方法“calculate()”。 我有多核系统。所以我想要线程的并行处理。

在上面的场景中,我能获得表现吗?所有线程都可以访问该方法在同一时间进行计算吗?

或者,由于A类是单例,因此需要阻塞线程等待。

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

5 个答案:

答案 0 :(得分:2)

这是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.
}

如果要使用并行处理(如果这是主要目标),则单例不是您应该使用的设计模式。

答案 1 :(得分:1)

我担心,像“单身人士需要同步”或“单身人士不需要同步”这样的陈述过于简单化了。只能从你处理单身模式的事实中得出结论。

对于多线程而言真正重要的是共享内容。如果执行计算的所有线程共享数据,则可能需要同步该访问。如果代码的关键部分不能在线程之间同时运行,那么您将需要同步它。

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

坏消息是这些事情非常复杂。抱歉。一个可能的参考:

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

答案 2 :(得分:1)

  

我在web / Stackoverflow中发现了类似的问题。但我无法得到明确的答案。

有充分的理由!!

由于单身,无法确定单身人士的方法是否需要同步

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

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

  • 如果没有,则不需要同步。


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

  // perform some calculation and update DB

......以及calculate()方法不带参数的事实。

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

更新数据库还需要某种同步。但是,这应该由JDBC连接对象和从中获取的对象来处理... 提供您遵守规则并且不尝试在多个线程之间共享连接。 (数据库更新也会出现并发瓶颈......假设更新适用于同一个或多个数据库表。)

答案 3 :(得分:0)

这取决于你如何实现Singleton。如果您使用Synchronized关键字,那么他们将不会等待。 使用Singleton进行初步初始化。

这样的事情:

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
  }
} 

以上将在多线程环境中表现良好。或者你可以去实现Singleton的枚举。

检查此链接是否有各种单例实现:http://javarevisited.blogspot.in/2012/07/why-enum-singleton-are-better-in-java.html

答案 4 :(得分:0)

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

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

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

另外请记住,由于您正在“更新数据库”,因此表级或行级锁也可能会限制并发性。

如果你担心表现,最好的办法是测试它。