您的位置:首页 > 其它

创建型模式.单例模式-懒汉、饿汉、枚举、原子

2018-03-28 00:00 399 查看

1 安全发布对象的四种方法

在多线程中,为了保证线程安全性,我们要正确地发布对象,保证发布地对象不要逸出。

在静态初始化函数中初始化一个对象引用

将对象的引用保存到volatile类型域或者AtomicReference对象中

将对象的引用保存到某个正确构造对象的final类型域中

将对象的引用保存到一个由锁保护的域中

2 懒汉单例模式

写法简单,适合简单、小的对象创建;

当创建一个非常复杂、非常大I/O操作、非常耗内存的对象时,不宜采用;

package com.dhm.singleton;

/**
* 懒汉单例模式
* @author duhongming
* @email 935720334@qq.com
*/
public class LazySingletonPattern {

//方法1 声明为常量
private static final LazySingletonPattern instance = new LazySingletonPattern();

//方法2 静态代码块
/*private static LazySingletonPattern instance = null;
static{
instance = new LazySingletonPattern();
}*/

//构造方法私有
private LazySingletonPattern(){}

public static LazySingletonPattern getInstance() {
return instance;
}
}


3 饿汉单例模式(volatile+双重检测机制)

适合绝大多数情况;

编写复杂,由于加锁,对性能有一定影响;

package com.dhm.singleton;

/**
* 饿汉单例模式(volatile+双重检测机制)
* @author duhongming
* @email 935720334@qq.com
*
* 创建对象过程:
* 1、memory = allocate()分配对象的内存空间
* 2、ctorInstance() 初始化对象
* 3、instance = memory 设置instance指向刚分配的内存
*
* 2和3会发生指令重排
*
* volatile作用:内存可见+防止指令重排
*/
public class HungrySingletonPattern {

/* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
private volatile static HungrySingletonPattern instance = null;

/* 私有构造方法,防止被实例化 */
private HungrySingletonPattern(){}

/* 因为我们只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字 */
private static synchronized void syncInit() {//同步锁,静态方法锁定作用域是对象
if (instance == null) {
instance = new HungrySingletonPattern();
}
}

/* 静态的工厂方法,创建实例 */
public static HungrySingletonPattern getInstance(){
if(instance == null){//双重检测机制
syncInit();
}
return instance;
}

/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
public Object readResolve(){
return instance;
}
}


4 枚举单例模式

终极解决方案,请使用!

package com.dhm.singleton;

/**
* 枚举单例模式
* @author duhongming
* @email 935720334@qq.com
*/
public class EnumSingletonPattern {

private EnumSingletonPattern(){}

public static EnumSingletonPattern getInstance() {
return Singleton.INSTANCE.getIntance();
}

private enum Singleton{

INSTANCE;

private EnumSingletonPattern instance;

//JVM保证这个只执行一次
Singleton(){
instance = new EnumSingletonPattern();
}

public EnumSingletonPattern getIntance(){
return instance;
}
}
}


5 原子布尔变量单例模式

呵呵,纯属娱乐!

package com.dhm.singleton;

import java.util.concurrent.atomic.AtomicBoolean;
/**
* 原子布尔变量单例模式
* @author duhongming
* @email 935720334@qq.com
*/
public class AtomicBooleanSingletonPattern {

private static final AtomicBoolean atomicBoolean = new AtomicBoolean(false);

private AtomicBooleanSingletonPattern(){}

private static AtomicBooleanSingletonPattern intance = null;

public static AtomicBooleanSingletonPattern getInstance() {
if(atomicBoolean.compareAndSet(false,true)){
intance = new AtomicBooleanSingletonPattern();
}
return intance;
}
}


6 单例模式在多线程下的测试

package com.dhm.singleton;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* 四种单例模式测试
* @author duhongming
* @email 935720334@qq.com
*/
public class SingletonPatternTest{
private static final HungrySingletonPattern hungrySingletonPattern = HungrySingletonPattern.getInstance();
private static final LazySingletonPattern lazySingletonPattern = LazySingletonPattern.getInstance();
private static final EnumSingletonPattern enumSingletonPattern = EnumSingletonPattern.getInstance();
private static final AtomicBooleanSingletonPattern atomicBooleanSingletonPattern = AtomicBooleanSingletonPattern.getInstance();

/**
* 初始化原子操作AtomicBoolean为false,只要有一个为false,
* 它就会置为true,只要不为true,我们单例模式都是可以正常运行的
*/
private static final AtomicBoolean atomicBoolean = new AtomicBoolean(false);

private static final int TEST_NUM = 1000000;
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
CountDownLatch countDownLatch1 = new CountDownLatch(TEST_NUM);
CountDownLatch countDownLatch2 = new CountDownLatch(TEST_NUM);
CountDownLatch countDownLatch3 = new CountDownLatch(TEST_NUM);
CountDownLatch countDownLatch4 = new CountDownLatch(TEST_NUM);

Long start1 = System.currentTimeMillis();
for (int i = 0; i < TEST_NUM; i++) {
executorService.execute(()->{
try{
doHungrySingletonPatternTest();
} finally {
countDownLatch1.countDown();
}
});
}
countDownLatch1.await();
System.out.println("doHungrySingletonPatternTest cost time:"+(System.currentTimeMillis()-start1));

Long start2 = System.currentTimeMillis();
for (int i = 0; i < TEST_NUM; i++) {
executorService.execute(()->{
try{
doLazySingletonPatternTest();
} finally {
countDownLatch2.countDown();
}
});
}
countDownLatch2.await();
System.out.println("doLazySingletonPatternTest cost time:"+(System.currentTimeMillis()-start2));

Long start3 = System.currentTimeMillis();
for (int i = 0; i < TEST_NUM; i++) {
executorService.execute(()->{
try{
doEnumSingletonPatternTest();
} finally {
countDownLatch3.countDown();
}
});
}
countDownLatch3.await();
System.out.println("doEnumSingletonPatternTest cost time:"+(System.currentTimeMillis()-start3));

Long start4 = System.currentTimeMillis();
for (int i = 0; i < TEST_NUM; i++) {
executorService.execute(()->{
try{
doAtomicBooleanSingletonPatternTest();
} finally {
countDownLatch4.countDown();
}
});
}
countDownLatch4.await();
System.out.println("doAtomicBooleanSingletonPatternTest cost time:"+(System.currentTimeMillis()-start4));

executorService.shutdown();

if(!atomicBoolean.get()){
System.out.println("单例模式测试通过!");
}else{
System.out.println("单例模式测试失败...");
}
}

private static void doHungrySingletonPatternTest(){
Boolean isEquals = hungrySingletonPattern.hashCode()==HungrySingletonPattern.getInstance().hashCode();
if(atomicBoolean.compareAndSet(isEquals,true)){
System.out.println("doHungrySingletonPatternTest fail");
}
}
private static void doLazySingletonPatternTest(){
Boolean isEquals = lazySingletonPattern.hashCode()==LazySingletonPattern.getInstance().hashCode();
if(atomicBoolean.compareAndSet(isEquals,true)){
System.out.println("doLazySingletonPatternTest fail");
}
}
private static void doEnumSingletonPatternTest(){
Boolean isEquals = enumSingletonPattern.hashCode()==EnumSingletonPattern.getInstance().hashCode();
if(atomicBoolean.compareAndSet(isEquals,true)){
System.out.println("doEnumSingletonPatternTest fail");
}
}
private static void doAtomicBooleanSingletonPatternTest(){
Boolean isEquals = atomicBooleanSingletonPattern.hashCode()==AtomicBooleanSingletonPattern.getInstance().hashCode();
if(atomicBoolean.compareAndSet(isEquals,true)){
System.out.println("doAtomicBooleanSingletonPatternTest fail");
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  单例模式
相关文章推荐