1.啥是设计模式
设计模式实际上就是程序员的棋谱,用来解决特定情况下的特定问题的通常方式,是一种特定的思维模式。
1.单例模式
单例模式是常问的面试题,单例模式就是保证在多个人创作项目的时候只会有一个实例对象,而不会创建出多个对象。单例模式的创建分为懒汉和饿汉。
1.饿汉模式:
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
private Singleton() {
}
}
在Singleton中创建实例对象,在类加载的时候就创建对象,通过静态static方法对外提供接口,用于获得instance对象。
这里的构造方法私有化是为了防止外部实例化Singleton对象。由于单例对象在类加载时就被创建,因此不存在线程安全问题。但如果实例很大且长时间未使用,会造成资源浪费。
2.懒汉模式:
懒汉模式是第一次被调用的时候才创建对象:
public class Singleton1 {
private static Singleton1 instance=null;
public static Singleton1 getInstance() {
if (instance==null){
instance=new Singleton1();
}
return instance;
}
}
懒汉模式和饿汉模式有着明显的差别,在这里饿汉模式在类加载的时候就创建好一个实例化对象了不存在线程安全的问题,但是饿汉模式由于线程在调用的时候是抢占式执行,就会出现线程安全的问题。
如果实例创建好了,后面在多线程环境调用getInstance就不再有线程安全问题了,因为不会再new实例了。
因此,加上synchronized 就能够解决这里的创建多个实例的问题。
优化1:加锁
public class Singleton1 {
private static Singleton1 instance=null;
public static Singleton1 getInstance() {
synchronized (Singleton1.class) {
if (instance == null) {
instance = new Singleton1();
}
}
return instance;
}
}
加锁了就能保证只创建出一个实例化对象,但是在后边已经创建出一个实例化对象之后,由于前面加了锁,还要进行加锁的判断而不是直接优先返回instance,所以我们可以再加锁。
优化2:再使用一个if语句判断,防止加锁带来的性能问题
public class Singleton1 {
private static Singleton1 instance=null;
public static Singleton1 getInstance() {
if (instance==null) {
synchronized (Singleton1.class) {
if (instance == null) {
instance = new Singleton1();
}
}
}
return instance;
}
}
优化3:给instance加上volatile关键字
关于涉及到了volatile那就是涉及到了内存可见性的问题,以及指令重排序,也是编译器的一种优化策略。
而在instance = new SingletonLazy(); 这行代码中,其实会有很多很多的指令,但是大体上可以分成三个步骤:
- 申请内存空间
- 调用构造方法(对内存空间进行初始化)
- 把此时内存空间的地址,赋值给 instance 引用
而在指令重排序的优化下,上述过程不一定是按 123 执行的,也可能是 132 执行(1一定先执行),这种优化策略,在单线程下都是没有问题的,但 132 在多线程下,可能就会引起bug。
3调用完了后还没掉用2,这时候还没有初始化,但是instance以及不是null了,但是别的线程这时候拿到instance,是一个没有调用构造方法进行初始化的的对象就会出现问题了。
public class Singleton1 {
private static volatile Singleton1 instance=null;
public static Singleton1 getInstance() {
if (instance==null) {
synchronized (Singleton1.class) {
if (instance == null) {
instance = new Singleton1();
}
}
}
return instance;
}
}
所以我们得加上volatile防止内存可见性和指令重排序。