基本的单例模式:
public class SingletonTest{
private static SingletonTestinstance;
private SingletonTest() {
}
public static SingletonTest getInstance() {
if (instance == null) {
instance = new SingletonTest();
}
return instance;
}
}
调用
public class Main {
public static void main(String[] args) {
SingletonTest singlonTest=SingletonTest.getInstance();
}
但是 这样在多线程模式下可能出现多实例的现象,模拟一下
public class Main {
static Set instanceSet =Collections.synchronizedSet(new HashSet());
public static void main(String[] args) {
long start = System.currentTimeMillis();
Thread threads[] = new Thread[1000] ;
for (int i = 0; i < 1000; i++) {
threads[i] = new MyThread();
}
for (int i = 0; i < 1000; i++) {
threads[i].start();
// System.out.println(threads[i].getName());
}
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "ms");
System.out.println(instanceSet.size());
for(Iterator i=instanceSet.iterator();i.hasNext();){
System.out.println(i.next());
}
}
}
class MyThread extends Thread {
public void run() {
SingletonTest a = SingletonTest.getInstance();
Main.instanceSet.add(a);
}
}
观察输出可以看到产生了多个实例。
防止这种多线程产生多实例的方法有:
1.方法前加 synchronized
public class SingletonTest{
private static SingletonTest instance;
private SingletonTest() {
System.out.println("create instance");
}
public static synchronized SingletonTest getInstance() {
if (instance == null) {
instance = new SingletonTest();
}
return instance;
}
}
这种效率较低 只能同时有一个线程调用getInstance 其实真正只要在 instance=new SingletonTest()同步。
2.在产生实例的地方加同步
public class SingletonTest {
private static SingletonTest instance = null;
private SingletonTest() {
System.out.println("create instance");
}
public static SingletonTest getInstance() {
if(instance==null){
synchronized(SingletonTest.class){
instance=new SingletonTest();
}
}
return instance;
}
}
这样处理有多线程时还是会产生多个实例
3.双重锁
public class SingletonTest {
private static SingletonTest instance = null;
private SingletonTest() {
System.out.println("create instance");
}
public static SingletonTest getInstance() {
if(instance==null){
synchronized(SingletonTest.class){
if(instance==null){
instance=new SingletonTest();
}
}
}
return instance;
}
}
这也不是完美无缺的,在java的内存模型里有可能出现多个实例
instance = new Singleton();java代码的过程可解释如下 3个步骤
1 mem = allocate(); //Allocate memory for Singleton object. % z$ S, _' s. D% A
2 instance = mem; //Note that instance is now non-null, but
//has not been initialized. * X% ]1 @( c+ T4 H" ~, I
3 ctorSingleton(instance); //Invoke constructor for Singleton passing instance. ! Z( m
- Thread 1 enters the
getInstance()
method. - Thread 1 enters the
synchronized
block at //1 becauseinstance
isnull
. - Thread 1 proceeds to //3 and makes instance non-
null
, but before the constructor executes. - Thread 1 is preempted by thread 2.
- Thread 2 checks to see if instance is
null
. Because it is not, thread 2 returns theinstance
reference to a fully constructed, but partially initialized,Singleton
object. - Thread 2 is preempted by thread 1.
- Thread 1 completes the initialization of the
Singleton
object by running its constructor and returns a reference to it.
4.早期初始化
public class SingletonTest{
private static SingletonTest instance = new SingletonTest();
private SingletonTest() {
System.out.println("create instance");
}
public static SingletonTest getInstance() {
return instance;
}
}
参考:http://www.ibm.com/developerworks/library/j-dcl.html?S_TACT=105AGX52&S_CMP=cn-a-j