只要类里面没得其它的static属性或方法,基本不需要考虑lazy load和thread safe,因为java字节码本来就是延时加载的,下面实现就行了。
public class Singleton { public static final Singleton so = new Singleton(); private Singleton(){} }
或者
public class Singleton { private static Singleton so = new Singleton(); private Singleton(){} public static Singleton getInstance {return so;} }
如果class Singleton里面有其它static属性或方法(这种情况几乎没有或者可以避免),这才考虑需不需要延时加载singleton对象,如果这些情况你都遇上了又确实不能忍受提前实例化。那就用holder class或double check(可以参考effective java(2e)中的item 71)。
下面是一个对单例的例子,有4中形式,转自一个回复,感觉好,自己就记录下来了,留给别人学习:
/** * @author lee * @date Mar 5, 201210:09:12 AM * @version V1.0 * @todo 单例模式属于对象创建型模式,其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点 */ public class Singleton { private static Singleton instance; private static Singleton instance1=new Singleton(); private static Singleton instance2; private static Singleton instance3; private volatile static Singleton instance4; //私有构造方法,避免外部创建实例 private Singleton(){ } //懒汉式单例>当需要的时候,并且发现没有实例的时候,才去初始化. 多线程下这种单例模式是起不到效果的 public static Singleton getInstance(){ if(instance==null){ threadSleep(); instance=new Singleton(); } return instance; } //饿汉式单例>管你需要不需要,反正我是饿了,类加载的时候就已经初始化,没有起到延迟加载的效果 public static Singleton getInstance1(){ return instance1; } //对懒汉式进行同步,牺牲了性能,同步的原则应该是尽量对代码块同步,不要对整个方法同步 public static synchronized Singleton getInstance2(){ if(instance2==null){ threadSleep(); instance2=new Singleton(); } return instance2; } //双重检查加锁DCL(double checking lock),只在第一次调用getInstance()时才要同步,提高性能 public static Singleton getInstance3(){ if(instance3==null){ threadSleep(); synchronized (Singleton.class) { if(instance3==null){ instance3=new Singleton(); } } } return instance3; } public static Singleton getInstance4(){ if(instance4==null){ threadSleep(); synchronized (Singleton.class) { if(instance4==null){ instance4=new Singleton(); } } } return instance4; } //让当前线程休眠1秒,模拟多个线程同时访问instance==null之后的临界情况 public static void threadSleep(){ try { System.out.println("当前线程休眠1秒!"); Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
上面几种是常见的单例写法,下面分别弄几个线程测试一下,
public class ThreadTest extends Thread { @Override public void run() { Singleton s=Singleton.getInstance(); System.out.println(s.toString()); /*Singleton s1=Singleton.getInstance1(); System.out.println(s1.toString());*/ /*Singleton s2=Singleton.getInstance2(); System.out.println(s2.toString());*/ /*Singleton s3=Singleton.getInstance3(); System.out.println(s3.toString());*/ } public static void main(String[] args) { for(int i=0;i<3;i++){ ThreadTest test=new ThreadTest(); test.start(); } } }
把RUN方法里的注释,去掉,一次执行一个方法,发现除了第一个在多线程环境下不能实现真正的单例,其他的方法都是可以的。。。
网上有说DCL方法在JAVA中也不能实现真正的单例,不过,这测试结果好像也是可以的。
对单例的讨论过多,现在就到这吧,还是应用上的才是王道。