单例模式介绍
所谓类的单例模式设计,就是采取一定的方法保证在整个系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态)
单例模式常用实现方式
饿汉式
步骤如下:
- 构造方法私有化
- 类内创建对象(创建就进行实例化)
- 向外提供一个静态公共方法
public class SingletonTest01 {
public static void main(String[] args) {
Singleton st=Singleton.getInstance();//类装载时便进行实例化
Singleton st2=Singleton.getInstance();
System.out.println(st==st2);
System.out.println(st.hashCode());
System.out.println(st2.hashCode());
}
}
class Singleton{
//饿汉式
//1.构造器私有化
private Singleton()
{
}
//2.本类内部创建对象实例
private final static Singleton instance =new Singleton();
//3。提供一个公有静态方法
public static Singleton getInstance()
{
return instance;
}
}
优点:线程安全(实现同步)
缺点:传参数困难,且容易造成内存浪费(装载即实例,但是有可能用不到)
懒汉式
步骤如下:
- 构造方法私有化
- 类内创建对象
- 向外提供一个静态公共方法(需要判断是否非空)
public class SingletonTest03 {
public static void main(String[] args) {
System.out.println("线程不安全!!!!");
Singleton st=Singleton.getInstance();//类装载时便进行实例化
Singleton st2=Singleton.getInstance();
System.out.println(st==st2);
System.out.println(st.hashCode());
System.out.println(st2.hashCode());
}
}
class Singleton{
private static Singleton instance;
private Singleton()
{
}
public static Singleton getInstance()
{
if(instance==null)
instance=new Singleton();
return instance;
}
}
优点:延迟加载
缺点:线程不安全(多线程下,若一个线程进入了if(singleton==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例)
同步方法
synchronized同步方法,每一次只允许一个线程访问。
public class SingletonTest04 {
public static void main(String[] args) {
Singleton st=Singleton.getInstance();
Singleton st2=Singleton.getInstance();
System.out.println(st==st2);
System.out.println(st.hashCode());
System.out.println(st2.hashCode());
}
}
class Singleton{
private static Singleton instance;
private Singleton()
{
}
public static synchronized Singleton getInstance()
{
//此方法效率低下
if(instance==null)
instance=new Singleton();
return instance;
}
}
优点:解决了线程不安全的问题
缺点:效率太低(每个线程在想获得类的实例的时候,执行getInstance()方法都要进行同步。其实只执行一次代码实例化就足够了。)
同步代码块
class Singleton
{
private static Singleton instance;
private Singleton()
{
}
public static Singleton getInstance()
{
if(instance==null)
{
synchronized(Singleton.class)
{
instance=new Singleton();
}
}
return instance;
}
}
写法错误,同步并不能起到真正的作用,实际开发不可用。
双重检查
class Singleton{
private static volatile Singleton instance;
private Singleton()
{
}
public static synchronized Singleton getInstance()
{
if(instance==null)//解决了效率低下
{
synchronized(Singleton.class)
{
if(instance==null)//双重检查,实现一次实例化
{
instance=new Singleton();
}
}
}
return instance;
}
}
实现了延时加载,与线程安全,同时保证了效率。
静态内部类
class Singleton
{
private static volatile Singleton instance;
private Singleton()
{
}
//外类装载不会马上装载的
private static class SingletonInstance{
private static final Singleton Instance=new Singleton();//饿汉式
}
//用到他的时候才装载(JVM装载时线程安全)
public static synchronized Singleton getInstance()
{
return SingletonInstance.Instance;//懒汉式
}
}
优点:
- 这种方法采用了类装载的机制来保证初始化实例时只有一个线程。
- 静态内部类在Singleton进行装载时并不会立即实例化,而是在需要进行实例化时,调用getInstance()方法,才会装载SingletonInstance类,从而完成实例化。
- 类的静态属性只会在第一次加载类的时候初始化,JVM保证了线程的安全,在类进行初始化时,别的线程是无法进入的。
这种方法也实现了延时加载与线程安全。
枚举方式
public class SingletonTest08 {
public static void main(String[] args) {
Singleton st=Singleton.Instance;
Singleton st2=Singleton.Instance;
System.out.println(st==st2);
System.out.println(st.hashCode());
System.out.println(st2.hashCode());
}
}
enum Singleton{//枚举实现单利
Instance;//属性
public void sayOK()
{
System.out.println("ok~");
}
}
优点:
枚举方式实现单例,不仅能够避免多线程同步问题,而且还能防止反序列化重新创建新的对象。