一个类中只有一个实例, 且能够自行实例化提供这个实例, 同时提供全局访问的方法.
结构
1.构造私有化: 确保外部不能使用new直接创建对象
2.内部静态属性创建实例
3.对外公共静态获取对象方法
demo
/**
* 单例模式
* 1. 构造私有化: 确保外部不能使用new直接创建对象
* 2. 内部静态属性创建实例
* 3. 对外公共静态获取对象方法
*
* @author liuzhihang
* @date 2018/3/27 17:45
*/
public class SingletonPattern {
private SingletonPattern() {
}
private static SingletonPattern singletonPattern = null;
public static SingletonPattern getSingletonPattern() {
if (singletonPattern == null) {
singletonPattern = new SingletonPattern();
}
return singletonPattern;
}
}
分类
1.懒汉式: 懒汉模式, 项目启动时不生成对象, 而是在首次创建该对象的时候生成唯一实例
/**
* 懒汉模式, 项目启动时不生成对象, 而是在首次创建该对象的时候生成唯一实例
*
* @author liuzhihang
* @date 2018/4/2 16:24
*/
public class LazyPattern {
private LazyPattern() {
}
private static LazyPattern lazyPattern = null;
public static LazyPattern getLazyPattern() {
try {
if (lazyPattern == null) {
// 模拟一系列耗时操作
Thread.sleep(50);
lazyPattern = new LazyPattern();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return lazyPattern;
}
}
2.饿汉式: 项目启动时, 进行加载, 会导致项目启动较慢, 并且无论后面是否用到都会进行加载
/**
*
* 饿汉式单例模式
* 项目启动时, 进行加载, 会导致项目启动较慢, 并且无论后面是否用到都会进行加载
*
* @author liuzhihang
* @date 2018/4/2 18:44
*/
public class HungerPattern {
private HungerPattern() {
}
private static HungerPattern hungerPattern = new HungerPattern();
public static HungerPattern getHungerPattern() {
return hungerPattern;
}
}
测试用例
在多线程情况下对单例模式进行测试:
/**
* @author liuzhihang
* @date 2018/3/27 19:02
*/
public class SingletonTest {
public static void main(String[] args) {
ThreadTest[] threadTests = new ThreadTest[10];
for (int i = 0; i < threadTests.length; i++) {
threadTests[i] = new ThreadTest();
}
for (int i = 0; i < threadTests.length; i++) {
threadTests[i].start();
}
}
}
class ThreadTest extends Thread {
@Override
public void run() {
// 懒汉模式
System.out.println(LazyPattern.getLazyPattern().hashCode());
// 饿汉模式
// System.out.println(HungerPattern.getHungerPattern().hashCode());
}
}
结果:
1.饿汉模式
D:\jdk1.8\bin\java.exe . . .
1294123621
1294123621
1294123621
1294123621
1294123621
1294123621
1294123621
1294123621
1294123621
1294123621
Process finished with exit code 0
2.懒汉模式
D:\jdk1.8\bin\java.exe . . .
140919816
1359128134
1385166630
924507082
67641385
508832262
574926395
140919816
1442414714
896298396
Process finished with exit code 0
懒汉模式的线程安全优化
饿汉模式会造成资源浪费, 启动慢等结果, 下面对懒汉模式进行线程安全优化.
synchronized 锁住静态方法
锁住静态方法 类级锁 影响范围较大, 导致效率相对较低
/**
* 懒汉式
* 在方法上添加 synchronized 关键字 锁类
* 同步方法的方式, 导致效率相对较低
*
* @author liuzhihang
* @date 2018/4/3 14:27
*/
public class SyncLazyPattern {
private SyncLazyPattern() {
}
private static SyncLazyPattern syncLazyPattern = null;
public static synchronized SyncLazyPattern getSyncLazyPattern() {
try {
if (syncLazyPattern == null) {
Thread.sleep(100);
syncLazyPattern = new SyncLazyPattern();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return syncLazyPattern;
}
}
synchronized 锁住代码块
package com.liuzhihang.demo.singleton;
/**
* 锁代码块的方式虽然可以保证结果一致性
* 但锁住很多操作, 同样会导致效率低下
*
* @author liuzhihang
* @date 2018/4/3 15:22
*/
public class SyncCodeBlockLazyPattern {
private SyncCodeBlockLazyPattern() {
}
private static SyncCodeBlockLazyPattern syncCodeBlockLazyPattern = null;
public static SyncCodeBlockLazyPattern getSyncCodeBlockLazyPattern() {
try {
// 锁住具体执行业务逻辑的代码
synchronized (SyncCodeBlockLazyPattern.class) {
if (syncCodeBlockLazyPattern == null) {
Thread.sleep(100);
syncCodeBlockLazyPattern = new SyncCodeBlockLazyPattern();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return syncCodeBlockLazyPattern;
}
}
双重检查锁机制(推荐)
package com.liuzhihang.demo.singleton;
/**
* 双重锁检查机制, 仅锁住创建对象的部分代码
* 注意: 在对象前 添加 volatile 关键字 确保可见性, 即 每次获取值从主内存中获取, 同时防止指令重排序
*
* @author liuzhihang
* @date 2018/4/3 15:29
*/
public class DubboCheckLockLazyPattern {
private DubboCheckLockLazyPattern() {
}
private static volatile DubboCheckLockLazyPattern dubboCheckLockLazyPattern = null;
public static DubboCheckLockLazyPattern getDubboCheckLockLazyPattern() {
try {
if (dubboCheckLockLazyPattern == null) {
// 一系列操作
Thread.sleep(100);
synchronized (DubboCheckLockLazyPattern.class) {
// 二次检查
if (dubboCheckLockLazyPattern == null) {
dubboCheckLockLazyPattern = new DubboCheckLockLazyPattern();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return dubboCheckLockLazyPattern;
}
}