单例模式
个人理解:单例模式实际就是通过类加载的方式获取到一个对象,并且保证这个对象在使用中只有一个,不允许再次被创建
一、懒汉模式
1、懒汉模式的基础写法
代码解释:
(1)、编写LazySingleton类的时候,需要将成员属性设定为static,这样才会是类属性
(2)、重写构造方法,将其设置为private,这样就防止其他人在new这个对象了,防止该类被重复new
package com.example.sheji.singleton.v1;
public class LazySingletonTest {
public static void main(String[] args) throws Exception {
LazySingleton instance = LazySingleton.getInstance();
LazySingleton instance1 = LazySingleton.getInstance();
System.out.println(instance);
System.out.println(instance1);
}
}
class LazySingleton{
private static LazySingleton instance;
private LazySingleton(){
}
public static LazySingleton getInstance() {
if(instance == null){
instance = new LazySingleton();
}
return instance;
}
}
执行结果:可以看到两个对象是一样的,懒汉模式已经基本实现。
但这样的写法在多线程环境下是有问题的!
当我们改为多线程的方式执行就会出现问题,对象居然不一样了
public class LazySingletonTest {
public static void main(String[] args) throws Exception {
Thread thread1 = new Thread(() -> {
LazySingleton instance = LazySingleton.getInstance();
System.out.println(instance);
});
Thread thread2 = new Thread(() -> {
LazySingleton instance = LazySingleton.getInstance();
System.out.println(instance);
});
thread1.start();
thread2.start();
}
}
class LazySingleton{
private static LazySingleton instance;
private LazySingleton(){
}
public static LazySingleton getInstance() {
if(instance == null){
instance = new LazySingleton();
}
return instance;
}
}
但如果我们让其中一个线程睡眠200ms呢,会发现对象的值又一样了
原因如下图,在两个线程都没有休眠的时候,因为执行太快,当第一个线程执行到if(instance == null)里面时,对象还没有new出来,第二个线程也执行到了,所以出现了这种情况
当让第二个线程休眠200ms的时候,第一个线程已经初始化好对象了,第二个线程就不需要初始化了
2、懒汉模式的升级写法
解释:
(1)、加锁synchronized ,当对象为空时,只允许一个线程先执行,其他线程等待,可以保证对象只被初始化一次
(2)、volatile 关键字,是为了防止指令重排序,防止instance 还没有开辟空间时,先被赋值了
class LazySingleton{
private static volatile LazySingleton instance;
private LazySingleton(){
}
public static LazySingleton getInstance() {
if(instance == null){
synchronized (LazySingleton.class){
if(instance == null){
instance = new LazySingleton();
}
}
}
return instance;
}
}
测试结果:
二、饿汉模式
public class HungrySingletionTest {
public static void main(String[] args) {
// HungrySingletion instance1 = HungrySingletion.getInstance();
// HungrySingletion instance2 = HungrySingletion.getInstance();
// System.out.println(instance2);
// System.out.println(instance1);
Thread thread = new Thread(() -> {
HungrySingletion instance1 = HungrySingletion.getInstance();
System.out.println(instance1);
});
Thread thread1 = new Thread(() -> {
HungrySingletion instance2 = HungrySingletion.getInstance();
System.out.println(instance2);
});
thread.start();
thread1.start();
}
}
class HungrySingletion{
private static HungrySingletion instance = new HungrySingletion();
private HungrySingletion(){
}
public static HungrySingletion getInstance() {
return instance;
}
}
执行结果:
解释:因为饿汉模式是在利用jvm在加载过程就已经自动初始化好了,所以不论是否使用多线程,都是一个对象