Java 性能问题:在多线程环境中使用Singleton对象
我有一个类“a”和方法“calculate()”。类是singleton类型(范围=singleton) 现在,我有一个程序可以创建20个线程。所有线程都需要访问“calculate()”方法。 我有多核系统。所以我想要线程的并行处理 在上述场景中,我可以获得性能吗?所有访问该方法的线程是否可以在同一时间实例中计算 或者,因为类A是单例的,所以线程需要在等待时被阻塞 我在web/Stackoverflow中发现了类似的问题。但我无法得到明确的答案。Java 性能问题:在多线程环境中使用Singleton对象,java,spring,singleton,Java,Spring,Singleton,我有一个类“a”和方法“calculate()”。类是singleton类型(范围=singleton) 现在,我有一个程序可以创建20个线程。所有线程都需要访问“calculate()”方法。 我有多核系统。所以我想要线程的并行处理 在上述场景中,我可以获得性能吗?所有访问该方法的线程是否可以在同一时间实例中计算 或者,因为类A是单例的,所以线程需要在等待时被阻塞 我在web/Stackoverflow中发现了类似的问题。但我无法得到明确的答案。 您能帮助我吗?这取决于您如何实现Singlet
您能帮助我吗?这取决于您如何实现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
}
}
在多线程环境中,上述功能将表现得非常好。或者,您可以使用Singleton的枚举实现
public class A{
public void calculate(){
//perform some calculation and update DB
}
}
查看此链接了解各种单例实现:这是单例的基本概念。系统(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.
}
如果您想使用并行处理(如果这是主要目标),那么singleton不是您应该使用的设计模式 像“单例需要同步”或“单例不需要同步”这样的说法恐怕过于简单化了。没有结论只能从你处理的是单身模式这一事实中得出
对于多线程来说,真正重要的是什么是共享的。如果执行计算的所有线程都共享数据,则可能需要同步该访问。如果有一些关键的代码段不能在线程之间同时运行,那么您需要同步这些代码段
好消息是,通常不需要同步整个计算中的所有内容。尽管需要同步部分操作,但您可能会从多核系统中获得显著的性能改进
坏消息是这些事情非常复杂。很抱歉一个可能的参考:
我在web/Stackoverflow中发现了类似的问题。但我无法得到明确的答案
这是一个很好的理由
无法确定单例上的方法是否需要由于是单例而进行同步
同步和对同步的需求都是关于可能由不同线程共享的状态
- 如果不同的线程共享状态(甚至是串行),则需要同步
- 如果没有,则不需要同步
您提供给我们的唯一线索可以帮助我们回答“是/否”,这是一条神秘的评论:
// perform some calculation and update DB
。。。而且calculate()
方法不带参数
如果我们推断calculate()
方法从单例本身的状态获取其输入,那么在检索该状态时,至少该方法的一部分(或它调用的方法)必须同步。但是,这并不意味着必须同步整个方法调用。calculate
方法需要锁定共享数据的时间比例将决定您实际可以获得多少并行性
数据库的更新也需要某种同步。但是,这应该由JDBC连接对象和您从中获得的对象负责。。。前提是您遵守规则并且不尝试在多个线程之间共享连接。(数据库更新还将出现并发瓶颈…假设更新应用于同一个或多个数据库表。)多个线程可以同时调用calculate() 除非执行某种类型的并发控制(使方法
synchronized
同步是一种选择),否则这些调用不会在该JVM中排队(串行执行)
对象是单例的事实可能会影响性能,也可能不会影响性能,这取决于该对象的属性(如果有的话)在calculate()中的使用方式
还要记住,由于您正在“更新数据库”,表或行级锁也可能会限制并发性
如果您担心性能,最好的办法就是测试它。A的实例是否线程安全?方法是否已同步??保存状态的单例需要同步…是的,实例是线程安全的。由于类A是单例的,所以在整个程序生命周期中只创建了一个类A的实例。Milan,我想知道它是否是一个传统的“Java单例类”或者一个枚举,或者您正在使用依赖注入框架(如Spring或Guice)来控制作用域?如果任何方法更改了一次可由多个线程访问的对象状态,则需要同步。对象是单核的事实与此无关。它是否在多核环境中提供性能。在多核中并行执行线程?这是一种访问单实例的解决方案。它没有回答OP关于是否
c的问题