零、什么是单例模式?
单例,单例,顾名思义这个类从头至尾只有一个实例。
单例模式具备以下三个特点:
-
私有化的构造函数
-
私有的静态的全局变量
-
公有的静态的方法
常用的三种单例模式:
-
懒汉模式(线程不安全)
-
饿汉模式(线程安全,资源利用率不高)
-
双重校验锁模式(线程安全,资源利用率高)
一、懒汉模式(线程不安全)
类加载的时候,“懒”的去创建一个实例;
当第一次被使用的时候我才给你创建实例,延迟加载
示例代码如下:
/**
* 懒汉式
* 线程不安全,延迟初始化
* @author :Negen
* @Date :Created in 15:25 2020/5/23
* @Description:
* @Modified By:
* @Version: 1.0
*/
public class SingletonLazy {
//私有的静态的全局变量
private static SingletonLazy instanse;
//私有化的构造函数
private SingletonLazy(){};
//公有的静态的方法
public static SingletonLazy getInstance(){
if (null == instanse){ //线程不安全触发点
instanse = new SingletonLazy();
}
return instanse;
}
}
二、饿汉模式(线程安全)
类加载的时候就创建一个实例;
创建的实例如果一直没有使用的话,就会造成资源浪费;
实例代码如下:
/**
* 饿汉模式
* 线程安全,常用
* 一开始就创建了实例,如果一直没用,就是产生的垃圾
* @author :Negen
* @Date :Created in 15:30 2020/5/23
* @Description:
* @Modified By:
* @Version: 1.0
*/
public class SingletonHungary {
private static SingletonHungary instance = new SingletonHungary();
private SingletonHungary(){};
public static SingletonHungary getInstance(){
return instance;
}
}
三、双重校验锁模式(线程安全)
对实例进程两次是否为空的检查;
第一次检查是为了防止不必要的锁;
第二次就是例行检查;
示例代码如下:
/**
* 双重检查模式
*
* 第一次:避免不必要的上锁
* 第二次:例行检查
* @author :Negen
* @Date :Created in 16:28 2020/5/23
* @Description:
* @Modified By:
* @Version: 1.0
*/
public class SingletonDoubleCheckLock {
private volatile static SingletonDoubleCheckLock instance;
private SingletonDoubleCheckLock(){};
public static SingletonDoubleCheckLock getInstance(){
if (null == instance){
synchronized (SingletonDoubleCheckLock.class){
if (null == instance){
instance = new SingletonDoubleCheckLock();
}
}
}
return instance;
}
}
四、线程不安全体现在哪儿?
如果有两个线程同时进入 if(instance == null)阶段,那么它们都会进入创建实例的阶段,从而导致创建多个不同的实例。
下面用多线程模拟了三种模式创建实例的结果
1、懒汉模式
示例代码:
public class TestLazy implements Runnable{
public static void main(String[] args) {
for (int i = 0; i<10; i++){
TestLazy test = new TestLazy();
new Thread(test).start();
}
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "----" + SingletonLazy.getInstance().toString());
}
}
打印结果:
懒汉模式结果.png十个线程中出现了三个不同的地址,说明“懒汉模式”线程不安全
2、饿汉模式
示例代码:
public class TestHungary implements Runnable{
public static void main(String[] args) {
for (int i = 0; i < 10; i++){
TestHungary test = new TestHungary();
new Thread(test).start();
}
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "----" + SingletonHungary.getInstance().toString());
}
}
打印结果:
[图片上传失败...(image-34b196-1590225907614)]
十个线程中出现的都是相同的地址,说明“饿汉模式”线程安全
3、双重校验锁模式
示例代码:
public class TestDoubleCheckLock implements Runnable{
public static void main(String[] args) {
for (int i = 0; i < 10; i++){
TestDoubleCheckLock testDoubleCheckLock = new TestDoubleCheckLock();
new Thread(testDoubleCheckLock).start();
}
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "----" + SingletonDoubleCheckLock.getInstance().toString());
}
}
打印结果:
[图片上传失败...(image-96367b-1590225907614)]
十个线程中出现的都是相同的地址,说明“双重校验锁模式”线程安全
网友评论