单例模式
定义:一种最最常见的一种模式,保证整个程序中只有一个实例
常见写法
1恶汉式
/**
* @author ${Li}
* 版本:1.0
* 创建日期:2020/4/8 21
* 描述:1.单例 模式 恶汉式
* 随着类的加载就已经 new 了对象
*/
public class SingleDemo {
public static SingleDemo mInstance = new SingleDemo();
private SingleDemo(){
}
public static SingleDemo getmInstance() {
return mInstance;
}
}
2懒汉式(1)
/**
* @author ${Li}
* 版本:1.0
* 创建日期:2020/4/8 21
* 描述:2.单例模式 懒汉式(1)
* 优点: 只有使用时才加载 效率更高
* 问题: 多并发可能会有多个实例
*/
public class SingleDemo {
private static SingleDemo mInstance ;
private SingleDemo(){
}
public static SingleDemo getmInstance() {
if (mInstance==null){//线程a进入还没有new SingleDemo(),
// b进入 mInstance为空 ab都创建了实例
mInstance = new SingleDemo();
}
return mInstance;
}
}
3.懒汉式(2)
/**
* @author ${Li}
* 版本:1.0
* 创建日期:2020/4/8 21
* 描述:2.单例模式 懒汉式(2) 解决 懒汉(1)的问题
* 优点: 利用锁解决(1)线程安全问题
* 问题: 每次调用都判断锁引起效率问题
*/
public class SingleDemo1 {
private static SingleDemo1 mInstance ;
private SingleDemo1(){
}
public static synchronized SingleDemo1 getmInstance() {
if (mInstance==null){//线程a进入还没有new SingleDemo(),
// b进入 mInstance为空 ab都创建了实例
mInstance = new SingleDemo1();
}
return mInstance;
}
}
4.懒汉式(3)
/**
* @author ${Li}
* 版本:1.0
* 创建日期:2020/4/8 21
* 描述:2.单例模式 懒汉式(3) 解决 懒汉(2)的问题
* 优点: 既保证线程安全效率也较高
* 问题: 还会可能出现多线程并发的问题,可能还是会存在多个实例
*/
public class SingleDemo2 {
private static SingleDemo2 mInstance ;
private SingleDemo2(){
}
public static SingleDemo2 getmInstance() {
if (mInstance==null){ //判断为空进来
synchronized (SingleDemo2.class){//加锁保证线程安全 只有1个能进入
if (mInstance==null){//再次判断是否为空,是空创建 创建后mInstance不为空
// 无法进入到synchronized锁里面来
mInstance = new SingleDemo2();
}
}
}
return mInstance;
}
}
5懒汉式(4)
/**
* @author ${Li}
* 版本:1.0
* 创建日期:2020/4/8 21
* 描述:2.单例模式 懒汉式(4) 解决 懒汉(3)的问题 终极版
* 优点: 既保证线程安全效率也较高 加 volatile字段
* 问题:
*/
public class SingleDemo3 {
// volatile字段作用
/* 1.防止重新排序的问题
java 正常初始化排序
(1)开辟内存空间
(2) 初始化对象
(3)给变量赋值(指向内存的地址)
java 可能出现的排序 2.3是可换的
先赋值在初始化对象 就会出现mInstance不为null 从而没有new的情况没有初始化
* 2.线程可见性 因为每一个线程都有各自的缓存区在改变对象时可能出现改变变量,
* 短时间另一个线程可能是不可见的(试例)
* */
private static volatile SingleDemo3 mInstance ;
private SingleDemo3(){
}
public static synchronized SingleDemo3 getmInstance() {
if (mInstance==null){ //判断为空进来
synchronized (SingleDemo3.class){//加锁保证线程安全 只有1个能进入
if (mInstance==null){//再次判断是否为空,是空创建 创建后mInstance不为空 无法进入到synchronized锁里面来
mInstance = new SingleDemo3();
}
}
}
return mInstance;
}
}
注意:
网上学习时候有很多例子都没有这个字段,在学习过程与查找资料中还是在里面加上了volatile字段,在查找资料和不断验证下我发现了这个例子
volatile实例
/**
* @author ${Li}
* 版本:1.0
* 创建日期:2020/4/8 22
* 描述:volatile 的例子 可以看出线程可见性
*/
public class VolatileDemo {
public static void main(String[] args) {
ThreadTestDemo ttd = new ThreadTestDemo();
new Thread(ttd).start();
while(true){
if(ttd.isFlag()){
System.out.println("------------------");
break;
}
}
// 不加volatile 输出为 flag=true
// 加 volatile 输出为 ------------------
// flag=true
}
}
class ThreadTestDemo implements Runnable {
// private volatile boolean flag = false;
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
6.静态内部类 (常用)
/**
* @author ${Li}
* 版本:1.0
* 创建日期:2020/4/8 22
* 描述:单例模式 静态内部类 (常用)
*/
public class SingleDemo {
private SingleDemo(){
}
private static class SingleDemoHolder{
private static volatile SingleDemo mInstance= new SingleDemo();
}
public static SingleDemo getInstance() {
return SingleDemoHolder.mInstance;
}
}
7.内部容器
package com.li.demol_day4_8.demo4;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;
/**
* @author ${Li}
* 版本:1.0
* 创建日期:2020/4/8 22
* 描述:单例模式内部容器
*/
public class SingleDemo {
private static Map<String, Object> objectMap = new HashMap<>();
static {
objectMap.put("mDemo", new SingleDemo());
}
private SingleDemo() {
}
public static Object getObjectMap(String key) {
return objectMap.get(key);
}
}
说明:
在学习过程中在网上找了很多资料看了很多大神的笔记,所以的技术基础都是类似的,这里就细说看了那个大神的博客了,反正看了很多的自己也是在学习中总结,可能在代码中会有问题 请发现问题多进行指正,交流学习,写博客的目的是碎片化记忆,能随时查找自己的笔记。接下来可能在此会写一系列的学习笔记,请多指教