单例的学习
1、单例是什么
单例,顾名思义,就是一个实例的意思,这样的优势在于节约内存,减少没有必要的创建对象。
2、单例的创建方式
1、饿汉式(也不知道为啥起这名字):其实就是程序启动时就创建了对象,使用时直接可以使用,特点是项目启动慢,调用块,由于不需要再次创建对象,直接调用即可,所以线程安全
public class User {
//初始化构造方法
private void User(){};
//项目启动就创建一个对象
private static User user = new User();
//开放一个对象的获取途径
public static User getUser(){
return user;
}
}
2、懒汉式:只有在第一次调用的时候,才会去创建对象,特点是项目启动块,调用慢,由于可能会多个线程同时创建对象,所以是线程不安全的,可以加锁来保证安全
public class User {
//初始化构造方法
private void User(){};
//项目启动就创建一个对象
private static User user;
//开放一个对象的获取途径
public static User getUser(){
if(user == null){
return user = new User();
}
return user;
}
}
3、懒汉式最终解决方案:双重锁
双重锁解决的问题:
两个线程同时访问,都判断对象为null,线程1先得到锁,第二次判断也为null,也就创建了对象并释放锁交给了线程2,线程2进锁后判断是否为null,发现不为null,也就返回对象啦,之后再去获取对象就不经过锁了,因为在锁外层已经判断不为null了
加volatile的作用:
volatile主要作用是可见性,也就是保证每次都在内存中读取类而不是从缓存中读取。
volatile还有一个作用是防止指令重排的问题,这就是在单例中增加volatile的作用,意义就是防止会出现先执行下面代码,再执行上面代码导致的问题。
public class User {
//初始化构造方法
private void User(){};
//项目启动就创建一个对象
private volatile static User user;
//开放一个对象的获取途径
public static User getUser(){
if(user == null){
synchronized (User.class){
if(user == null) {
return user = new User();
}
}
}
return user;
}
}