单例模式不用多说,就是只存在一个对象,在任何情况下,拿到这个对象的实例都是同一个对象。
首先看最简单的情况,该对象只会同时被一个线程访问。我们可以写出如下的单例模式的代码:
public class SingleTon {
private SingleTon(){}
private static SingleTon instance ;
public static SingleTon getInstance(){
if(instance == null){
instance = new SingleTon();
}
return instance ;
}
}
在单线程的情况可以使用以上的代码,但是遇到多线程就不行了,假设两个线程同时进行到 if(instance==null) 然后我们就能得到两个实例,显然这是不对的,如果在面试中写出这样的代码,简直就是offer killer。
既然上述的代码在多线程的情况下不能正常的工作,我就还需要对代码进行处理,最简单的方法就是加锁:
</pre><pre name="code" class="java">public class SingleTon {
private SingleTon(){}
private static SingleTon instance ;
public static SingleTon getInstance(){
synchronized(SingleTon.class){
if(instance == null){
instance = new SingleTon();
}
}
return instance ;
}
}
在上面的代码中我们看到加上同步关键字以后就能保证不会产生两个对象了,但是新的问题来了,虽然这段代码保证了正确性单同事也带来了负面的影响,性能的下降,因为在同一时刻只能有一个线程访问,每次访问的时候都会加锁,加锁是一个非常耗时的操作,在可能的情况下我们希望尽量减少加锁的次数,
public class SingleTon {
private SingleTon(){}
private static SingleTon instance ;
public static SingleTon getInstance(){
if(instance == null){
synchronized(SingleTon.class){
if(instance == null){
instance = new SingleTon();
}
}
}
return instance ;
}
}
这样只有在判断到instance 为 null 的时候才对创建过程进行加锁,这样就能大大的减少加锁的次数,这可以算是比较不错了,但是我们还是希望有更好一些的解决方案,能不能不加锁,很幸运,确实有,我们可以使用饿汉式来创建对象,
public class SingleTon {
private SingleTon(){}
private static SingleTon instance = new SingleTon() ;
public static SingleTon getInstance(){
return instance ;
}
}
这样instance对象在类加载的时候就进行了初始化,而且能保证之后只有一个实例对象,而且不会出现并发下的异常与执行效率的问题,但是我们如果使用到的是该类的其他的静态方法,而并不会使用类的任何实例对象,那么这个对象依然会被创建,那我们能不能只在使用到该对象的时候进行对象的创建呢,答案是肯定的啦,
public class SingleTon {
private SingleTon(){}
public static SingleTon getInstance(){
return SingleTonHolder.instance ;
}
private static class SingleTonHolder{
private static SingleTon instance = new SingleTon();
}
}
It‘s over. 好啦,到这里算是成功了。
public class SingleTon {
private static boolean hasInstance = false ;
private SingleTon(){
/*
*防止反射生成多对象
*/
synchronized (SingleTon.class) {
if(hasInstance) throw new RuntimeException("create multi obj is not allowed !") ;
hasInstance = true ;
}
}
public static SingleTon getInstance(){
return SingleTonHolder.getInstance() ;
}
/**
* 懒加载,线程安全
* @author jianwei.tan
*
*/
private static class SingleTonHolder{
private static final SingleTon instance = new SingleTon();
private static final SingleTon getInstance(){
return instance ;
}
}
/**
* 防止反序列化多实例
* @return
*/
private Object readResolve() {
return SingleTonHolder.instance ;
}
}