2

我有一个带有方法“calculate()”的类“A”。A 类是单例(Scope=Singleton)类型。

public class A{ 

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

}

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

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

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

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

4

5 回答 5

3

恐怕像“单身人士需要同步”或“单身人士不需要同步”这样的陈述过于简单化了。仅从您正在处理单例模式这一事实无法得出任何结论。

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

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

坏消息是这些事情非常复杂。对不起。一种可能的参考:

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

于 2013-06-10T04:38:19.040 回答
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.
}

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

于 2013-06-10T04:37:07.283 回答
1

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

这是有充分理由的!!

不能说单例上的方法是否需要因为是单例而同步。

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

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

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


您向我们提供的唯一可以帮助我们回答是/否的线索是这条神秘的评论:

  // perform some calculation and update DB

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

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

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

于 2013-06-10T05:28:34.943 回答
0

这取决于你如何实现单例。如果您使用 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

于 2013-06-10T04:26:03.467 回答
0

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

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

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

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

如果您担心性能,最好的办法是对其进行测试。

于 2013-06-10T06:12:10.090 回答