把设计模式撸一遍,先从简单的开始。
单例模式怕是面试常考的模式之一了。动不动就让你写个单例模式。
首先来了解一下单例模式,可以理解为单例模式就是整个程序运行到结束这个实例只有0或者1个。说到这来,就必须考虑另一个东西,就是多线程的时候。像ArrayList。当CPU运行速度加上线程访问多的时候,怎么保证这个对象的实例只存在1或者0呢。单例模式就是了解决这些。
单例模式基本写法:
1:构造器方法设置private,不能让外部new实例化
2:一个static方法返回实例,总得让外部使用
知道这两点就好写了。
饿汉模式:还没有开始,就实例化。通常是用
private static 类名 ; 静态字段
public class Singleton {
/**
* 静态 属性 类加载的时候就实例化 对象
*/
private final static Singleton INSTANCE = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return INSTANCE;
}
}在类加载的时候就完成实例化。没有做到延迟加载。
也可以用静态代码块
public class Singleton2 {
private static Singleton2 singleton2;
static {
singleton2 = new Singleton2();
}
private Singleton2(){}
public static Singleton2 getInstance(){
return singleton2;
}
}学习单例模式,也可以顺带熟悉一下类的加载顺序。
说完饿汉模式,再说说懒汉模式,可以理解为。让它动一下,才去实例化,懒汉模式是为了延迟加载出现的。
public class Singleton4 {
private static Singleton4 singleton4 ;
private Singleton4(){}
private static Singleton4 getSingleton4(){
if (singleton4 == null){
singleton4 = new Singleton4();
}
return singleton4;
}
}在实例化的时候,对对象做了一下空判断,当没有这个实例的时候再创建实例。但这个也就有有个问题。饿汉模式,可以看到它对对象的实例只会有一次,虽然懒汉模式是做了空判断,再去实例化,但是在多线程的情况下就可能出现两种实例。
private static synchronized Singleton5 getSingleton5(){ if (singleton5 == null){
singleton5 = new Singleton5();
}
return singleton5;
}在调用方法的时候执行同步代码块。效率太低了
private static Singleton5 getSingleton5(){
if (singleton5 == null){
//A线程进入 去实例化 A还没有实例化完成时 B线程相继进入
synchronized(Singleton5.class){
singleton5 = new Singleton5();
}
}
return singleton5;
}在判断空后做加锁处理,当通过了 == null 判断,第二条也进来了,变会出现多个实例但也可能还出现多个实例。
最好的方法便是双层锁
public static Singleton6 getSingleton6(){
if (singleton6 == null){
synchronized (Singleton6.class){
if (singleton6 == null){
singleton6 = new Singleton6();
}
}
}
return singleton6;
}这样判断第一个是否有实例没有存在。有两条线程同时通过的时候,A线程创建完成。能及时锁住。
还有一种 是静态类部
public class Singleton7 {
private Singleton7(){}
private static class SingletonInstance{
static {
System.out.println("SingletonInstance");
}
private static final Singleton7 INSTANCE = new Singleton7();
}
public static Singleton7 getInstance(){
System.out.println("getInstance");
return SingletonInstance.INSTANCE;
}
}在外部调用的时候,去调用静态类部类,只有调用的时候,静态类部类才实例化。而静态类部类也像是饿汉模式一样,对于静态内部类没有延迟加载,但是对于Singleton7对来说是有延迟加载的。
基本都是在下面的链接学的,标准请看下面的,谢谢: