我正在尝试实现单例模式的示例。我们的一个问题是运行两个线程,每个线程调用getInstance()并验证只创建了一个Singleton对象的实例。
这是我的Singleton代码;
public class OurSingleton {
static OurSingleton ourSingleton;
static int instanceCounter;
private OurSingleton(){
instanceCounter++;
}
public static synchronized OurSingleton GetSingletonInstance(){
if( ourSingleton == null){
ourSingleton = new OurSingleton();
}
return ourSingleton;
}
public static int getCounter() {
return instanceCounter;
}
}
我的主人;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
OurSingleton mySingleton = null;
Thread one = new Thread(new GetSingletonInstance(mySingleton));
Thread two = new Thread(new GetSingletonInstance(mySingleton));
one.start();
two.start();
System.out.println("Main: " + mySingleton.getCounter());
}
}
class GetSingletonInstance implements Runnable {
int count = 0;
OurSingleton singleton;
public GetSingletonInstance(OurSingleton ourSingleton){
singleton = ourSingleton;
}
@Override
public void run() {
try {
while (count < 5000000) {
singleton.getSingletonInstance();
count++;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Thread: " + singleton.getCounter());
}
}
当我运行此代码时,我得到以下输出;
Main:0 Thread:1 Thread:1
有人可以解释这个输出的原因吗?我认为只有单一的Singleton实例存在。这是否意味着在线程中创建了另一个对象?任何建议表示赞赏!
答案 0 :(得分:8)
您应该避免同步getInstance
方法(因为只是为了在初始化后获取实例,这只是一个不必要的开销)。以下是懒惰初始化单例的推荐方法:
public class OurSingleton {
private OurSingleton() { }
public static OurSingleton getInstance() {
return Holder.instance;
}
private static class Holder {
private static OurSingleton instance = new OurSingleton();
}
}
答案 1 :(得分:5)
认为只有单一的Singleton实例存在。 这是否意味着在线程中创建另一个对象??
JVM中只存在一个单例实例;每个线程都显示只有一个实例的事实。
在Java中实现Singleton Pattern的最简单,最安全的方法是使用枚举:
public enum MySingleton {
INSTANCE;
public void doStuffHere() {
//...
}
}
public class ClientClass {
public void myMethod() {
MySingleton mySingleton = MySingleton.INSTANCE;
mySingleton.doStuff();
}
}
你只有一个MySingleton实例,它是线程安全的。
答案 2 :(得分:4)
您已从同一个类创建了2个线程实例。每一个都打印单个对象的实例数。数字为1表示您确实只创建了一个实例,以便正确实现您的单例。 你打印了两次,因为你创建了2个线程。
如果您想避免将移动线System.out.println(...)
混淆到主方法。
答案 3 :(得分:2)
只有一个OurSingleton
实例,但类getSingletonInstance
(使用适当的CAPS!)本身并不是单例。这是你放置柜台的那个。
答案 4 :(得分:2)
我会这样解释:
当您加载类OurSingleton
时,静态计数器getInstanceCounter
被初始化为零。然后,有多少次您获得该类的新实例,计数器始终为1,表示您确实是一个单身人士。
我建议进行以下更改
ourSingleton
,getInstanceCounter
答案 5 :(得分:2)
请看另一个答案,了解如何做得更好,对于你的问题,为什么要得到这个输出
Main: 0
Thread: 1
Thread: 1
代码
static int getInstanceCounter;
您正在设置声明并将静态变量设置为零。因此,在创建OurSingleton的任何实例之前,getInstanceCounter的值为零。 当你打电话
System.out.println("Main: " + mySingleton.getCounter());
没有创建OurSignleton的实例,因此mySignleton.getCounter()仍为零。
运行其中一个或两个线程将导致创建一个OurSingleton实例,并且getInstanceCounter将为一个。
你的单身人士正在工作。虽然在其他答案中提到了更好的方法。
除了一些关于你的代码的东西,它可能看起来很挑剔,但会帮助其他人阅读你的代码。
请变量私有
static int getInstanceCounter; =&GT;
private static int getInstanceCounter;
不应使用get
命名变量 private static int getInstanceCounter; =&GT;
private static int instanceCounter;
不要在类的实例上引用静态方法
mySingleton.getCounter()=&gt;
OurSingleton.getCount()
这也意味着永远不应该引用从未赋值的变量mySingleton,应该删除它。
public GetSingletonInstance(OurSingleton ourSingleton){
singleton = ourSingleton;
}
=&GT;
public GetSingletonInstance(){
singleton = OurSingleton.getInstance();
}
答案 6 :(得分:0)
通过OurSingleton.getInstanceCounter
(静态成员函数)对OurSingleton.getCounter ()
(静态成员)的访问不同步。这是唯一重要的事情。你的程序的其余部分简直使事情复杂化。请注意,在main
中,您通过mySingleton.getCounter ()
在null
指针上调用静态函数! mySingleton
永远不会有null
以外的其他值。
您应该使用enum
来实现单例模式,或者至少只使用一个静态变量,即持有单例对象的静态变量。