1.介绍
单例模式,是23中设计模式中比较重要的设计模式,单例其实就是单一实例,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
java中的RunTime类就使用了单例模式
2.写法
1)饿汉式
public class Singleton {
/**
* 1)构造器私有化
* 2)自行创建,并且用静态变量保存
* 3)对外提供这个实例
* 4)强掉这是一个单例,我们可以用final修饰
*/
public static final Singleton INSTANCE = new Singleton();
private Singleton(){
}
}
public class MainTest {
public static void main(String[] args) {
Singleton instance=Singleton.INSTANCE;
Singleton instance1 = Singleton.INSTANCE;
System.out.println(instance);
System.out.println(instance1);
}
}
//控制台输出
cn.nlg.test.Singleton@1540e19d
cn.nlg.test.Singleton@1540e19d
特点:
a)在这个类初始化时就创建了对象, 每次调用都返回同一个对象
b)如果没有使用到这个对象会浪费内存空间
2)懒汉式
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
//这里多线程环境下会有线程安全问题,单线程没问题
public static Singleton getInstance() {
if(instance == null){
instance =new Singleton();
}
return instance;
}
}
public class MainTest {
public static void main(String[] args) {
Singleton instance=Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance);
System.out.println(instance1);
}
}
//控制台输出
cn.nlg.test.Singleton@1540e19d
cn.nlg.test.Singleton@1540e19d
特点: 多线程的环境下会存在线程安全问题,这个适用于单线程
3)双检锁
class Singleton {
public volatile static Singleton instance = null;
public Singleton(){ }
public static Singleton getInstance(){
//外层判断是为了让instance不为空时无需等待
if(instance == null){
//使用synchronized关键字,保证了每次只有一个线程操作
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
//主方法测试
public class MainTest {
public static void main(String[] args) {
Singleton instance=Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance);
System.out.println(instance1);
}
}
//控制台输出
cn.nlg.test.Singleton@1540e19d
cn.nlg.test.Singleton@1540e19d
特点:1)解决了线程安全问题
b)volatile是为了防止指令重排,可以去了解一下volatile关键字的作用
4)静态内部类
public class Singleton{
private Singleton(){}
//静态内部类
private static class Inner{
private static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return Inner.INSTANCE;
}
}
//主方法测试
public class MainTest {
public static void main(String[] args) {
Singleton instance=Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance);
System.out.println(instance1);
}
}
//控制台输出
cn.nlg.test.Singleton@1540e19d
cn.nlg.test.Singleton@1540e19d
特点:a)这是懒汉式中比较推荐的写法
b)外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE
5)枚举
public enum Singleton {
INSTANCE;
}
//主方法测试
public class MainTest {
public static void main(String[] args) {
Singleton instance=Singleton.INSTANCE;
Singleton instance1 =Singleton.INSTANCE;
System.out.println(instance);
System.out.println(instance1);
}
}
重写了toString方法,控制台输出
INSTANCE
INSTANCE
特点 :a) enum 类型是线程安全的,因为Java 类的加载和初始化过程都是线程安全的(反编译一下枚举类)
b)饿汉式中比较推荐的写法
例子:
枚举类:
public enum T {
SPRING,SUMMER,AUTUMN,WINTER;
}
反编译之后的枚举类:
public final class T extends Enum
{
//省略部分内容
public static final T SPRING;
public static final T SUMMER;
public static final T AUTUMN;
public static final T WINTER;
private static final T ENUM$VALUES[];枚举类型和泛型 < 228
static
{
SPRING = new T("SPRING", 0);
SUMMER = new T("SUMMER", 1);
AUTUMN = new T("AUTUMN", 2);
WINTER = new T("WINTER", 3);
ENUM$VALUES = (new T[] {
SPRING, SUMMER, AUTUMN, WINTER
});
}
}
1.枚举类型T不可被继承
2.T中所有属性都被 static final
修饰