模式设计
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式的实现方式
1.饿汉式(静态常量)
饿汉模式:像一个饿汉一样,不管需不需要用到实例都要先去创建实例,即在类产生的时候就创建好实例,这是一种空间换时间的做法。
代码
public class Singleton {
//私有化构造方法,让外部无法直接访问
private Singleton(){
}
//创建静态的实例对象
private static Singleton singleton=new Singleton();
//创建静态的方法返回类中以及创建好的实例对象,让外部通过该方法访问
public static Singleton getInstance() {
return singleton;
}
}
优点:书写比较简单,类加载是就实例化。避免了线程同步问题。
缺点:类装载时就完成了实例化,如果从始至终都没使用果该类,则会造成资源的浪费。
结论: 这种方法可用,是线程安全的,但是可能造成内存浪费
2.饿汉式(静态代码块)
代码
public class Singleton {
//私有化构造方法,让外部无法直接访问
private Singleton(){
}
//声明类的实例变量
private static Singleton singleton;
//将对象的实例化方法在静态代码块中
static{
singleton = new Singleton();
}
//创建静态的方法返回类中以及创建好的实例对象,让外部通过该方法访问
public static Singleton getInstance() {
return singleton;
}
}
优缺点:这种方法与上面的饿汉式(静态常量)有些类似,只是将实例化对象放到了静态代码块中。优缺点和上面是一样。
结论: 这种方法可用,是线程安全的,但是可能造成内存浪费
3.懒汉式(线程不安全)
懒汉式,就是需要用到该实例时才去创建,如果有则返回,没有则新建。有线程安全和线程不安全两种写法。
代码
public class Singleton {
//私有化构造方法,让外部无法直接访问
private Singleton(){
}
//声明类的实例变量
private static Singleton singleton=null;
//将对象的实例化方法在静态代码块中
//创建静态方法返回实例对象
//先判断实例变量是否为null,如果是则实例化对象
public static Singleton getInstance() {
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
缺点:如果在多线程下,一个线程进入了 if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式
结论:在实际开发中,不要使用这种方式
4.懒汉式(线程安全、同步方法)
代码
public class Singleton {
//私有化构造方法,让外部无法直接访问
private Singleton(){
}
//声明类的实例变量
private static Singleton singleton=null;
//将对象的实例化方法在静态代码块中
//创建静态方法返回实例对象
//先判断实例变量是否为null,如果是则实例化对象
// 提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
public static synchronized Singleton getInstance() {
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
优点:解决了线程安全问题
缺点:效率太低啦,每个线程想获得类的实例时,执行getInstance()方法都要进行同步。大大降低了同步效率
结论:在实际开发中,不推荐使用这种方式
5.懒汉式(双重效验锁)
代码
public class Singleton {
//私有化构造方法,让外部无法直接访问
private Singleton(){
}
//使用volatile修饰singleton保证可见性,提高效率
private static volatile Singleton singleton = null;
public static Singleton getSingleton() {
if (singleton==null) {
synchronized (Singleton.class) {
//为了保证单例,返回的是同一个对象
if (singleton==null) {
singleton=new Singleton();
}
}
}
return singleton;
}
}
Double-Check 概念是多线程开发中常使用到的,如代码中所示,我们进行了两次 if (singleton == null)检查,这样就可以保证线程安全了。
这样,实例化代码只用执行一次,后面再次访问时,判断 if (singleton == null),直接 return 实例化对象,也避免的反复进行方法同步.
线程安全;延迟加载;效率较高
结论:在实际开发中,推荐使用这种单例设计模式
6.静态内部类
代码
public class Singleton {
//私有化构造方法,让外部无法直接访问
private Singleton(){
}
//通过内部类维护单例JVM在类加载的时候,是互斥的,所以可以保证线程安全问题
private static class SingleTon{
private static Singleton singleton = new Singleton();
}
//提供一个静态的公有方法,直接返回 SingletonInstance.singleton
public static synchronized Singleton getInstance() {
return SingleTon.singleton;
}
}
这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM 帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
结论:推荐使用.
7.枚举
代码
public enum Singleton {
singleton;
public void geteverMethod() {
}
}
这借助 JDK1.5 中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式
结论:推荐使用