一、概念:单例模式是一种创建型设计模式,费模式可以保证一个类有且只有一个实例对象。
GoF对该模式的定义:保证一个类只有一个实例存在,并且同时提供能对该实例进行访问的全局方法。
二、实现的三种方法
1.饿汉式
(1)代码实现
public class Singleton{
private static final Singleton st = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return st;
}
}
(2)分析
优点:这种写法简单,在类加载阶段就完成了实例化,避免了线程同步的问题。
缺点:在类加载的时候就完成了实例化,没有达到懒加载(延时加载)的效果。如果从始至终都没使用该实例,就会造成内存浪费。
2.0懒汉式
(1)代码实现
public class Singleton{
private static Singleton st;
private Singleton(){}
private static getInstance(){
if(st == null){
st=new Singleton();
}
return st;
}
}
(2)分析
优点:这种方法比较于第一种方法,实现了懒加载。
缺点:这种方法只能在单线程中使用,当多线程时,多个线程可能会同时进入if语句中,同时创建多个实例,与单例有所违背,所以不适合多线程。
2.1使用线程同步来保证线程安全
(1)实现方法
public class Singleton{
private static Singleton st;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(st==null){
st=new Singleton();
}
return st;
}
}
(2)分析
优点:解决了懒汉式的线程不安全。
缺点:效率太低,每个线程获得该类的实例时都要进行同步。
3.双检查锁
(1)代码实现
public class Singleton{
private static Singleton st;
private Singleton(){}
public static Singleton getInstance(){
if(st= =null){
synchronized(Singleton.class){
if(st= =null){
st=new Singleton();
}
}
}
return st;
}
}
(2)分析:从表面上看,在执行代码时,先判断st对象是否为空,为空在进行初始化,即使是在多线程的环境下,因为使用了Synchronized锁进行同步,该方法也是仅仅创建一个实例对象。但是从根本上这样写还是有问题的,运行的过程可以分为:a.分配对象内存空间;b.初始化对象;c.设置st指向刚分配的内存地址;其中b和c两步骤可能会发生重排现象,执行顺序为a、c、b,所以会引起线程判断地址为空时创建多个对象。
解决方案:
方案一、不允许b和c进行重排,使用volatile关键字,使用volatile修饰st后,之前的b和c重排在多线程下被禁止。
public class Singleton{
private static volatile Singleton st;
//剩下的代码不变
}
方案二、允许b和c重排,但重排不允许被其它线程看到。静态内部类方式在Singleton类被加载时并不会立即实例化。而是在需要实例化时,调用getInstance方法才会装在SingletonHolder类,从而完成Singleton的实例化。类的静态属性只会在第一次加载类的时候被初始化,所以在这里,JVM帮助我们保证了线程安全,在类进行初始化时,不允许其它线程访问。
public class Singleton{
public static class SingletonHolder(){
private static final Singleton INSTANCE=new Singleton();
}
public static getInstance(){
return SingletonHolder.INSTANCE;
}
}
设计模式--单例模式(Java)
最新推荐文章于 2024-01-23 10:00:27 发布