java 单例模式

2016-09-10  本文已影响27人  不懂zhuang懂的年岁

单例模式有以下特点:
1.单例类只能有一个实例(该类只能有一个实例)
2.单例类必须自己创建实例
3.单例类必须给所有其他对象提供这一实例
计算机系统中,如线程池、缓存、日志对象、驱动程序等被设置成单例。在多线程环境下,可能有一些同步问题。
如下代码所示:

public class TestStream {
     private String name;
     public String getName() {
         return name;
     }
     public void setName(String name) {
         this.name = name;
     } 
     //该类只能有一个实例
     private TestStream(){}    //私有无参构造方法
     //该类必须自行创建
     //有2种方式
     /*private static final TestStream ts=new TestStream();*/
     private static TestStream ts1=null;//懒汉单例模式
     //这个类必须自动向整个系统提供这个实例对象
     public static TestStream getTest(){//这里用的是懒汉单例模式
         if(ts1==null){
             ts1=new TestStream();
         }
         return ts1;
     }
     public void getInfo(){
         System.out.println("output message "+name);
     }
 }
public class TestMain {
     public static void main(String [] args){
         TestStream s=TestStream.getTest();
         s.setName("张孝祥");
         System.out.println(s.getName());
         TestStream s1=TestStream.getTest();
         s1.setName("张孝祥");
         System.out.println(s1.getName());
         s.getInfo();
         s1.getInfo();
         if(s==s1){
             System.out.println("创建的是同一个实例");
         }else if(s!=s1){
             System.out.println("创建的不是同一个实例");
         }else{
             System.out.println("application error");
         }
     }
 }

运行结果: 
张孝祥  
张孝祥  
output message 张孝祥  
output message 张孝祥  
创建的是同一个实例
懒汉单例模式:默认不自动实例化,等用的时候根据当前情况实例化

public class Singleton{
  private static Singleton instance = null;
  private Singleton(){}
  public static Singleton getInstance(){
    if(instance == null)  
        return new Singleton();
     else
        return instance;
}
}

饿汉单例模式:在类第一次加载的时候强制实例化

public class Singleton{
  private static Singleton instance = new Singleton();
  private Singleton(){}
  public static Singleton getInstance(){
        return instance;
}
}

单例模式的线程同步问题:
两个线程,一个发现变量是null,准备创建变量,第二个也发现变量是null,创建变量,就会造成在一个JVM中有多个单例类型的实例。
解决线程安全的方案:
1.使用synchronized方法对getInstance()方法进行同步

public class Singleton{
  private static Singleton instance = null;
  private Singleton(){}
  public synchronized  static Singleton getInstance(){
    if(instance == null)  //mark1
        return new Singleton();//mark2
     else
        return instance;
}
}

2.双重锁
但是用synchoronized会导致性能下降,我们想要的只是mark1和mark2的同步,所以可以不把synchronized加在方法上,而是加在代码块里

public class Singleton{
  private static volatile Singleton instance;
  
  private static Singleton(){}
  
  public static Singleton getSingleton(){
      if(instance == null){//mark1
        synchronized(Singleton.class){
            if(instance == null)//mark2
  return new Singleton();
             return instance;
}
return instance;
}    

}
}

这里用了两个判断,原因:如果两个线程同时到达mark1处,synchronized可以保证线程不同时进行,但两个线程会一个个执行,所以还要在synchronized代码块中再次判断,防止创建两个。
这个也叫作双重锁。
3.使用静态内部类
这种方法拥有单例、延迟创建(参见饿汉模式)和线程同步的优点,利用静态内部类来实现

public class Singleton{
    private static Singleton(){}
    
    private static class Lazyholder{
     private static final Singleton instance = new Singleton();
}

  public static Singleton getSingleton(){
  return Lazyholder.instance;
}
}

当类被加载时,由于没有static代码,所以不会有操作。当第一次执行getSingleton()方法时,内部静态类会被加载,创建外部单例类实例,在内部类加载过程中,静态类只会被加载一次,static属性和static初始化块的执行是串行的,这就保证了不会有两个线程同时new Singleton()

上一篇下一篇

猜你喜欢

热点阅读