设计模式--单例模式

文章介绍了Java中两种单例模式的实现:饱汉模式通过静态初始化确保只有一个实例,而饿汉模式则在类加载时创建单例。文章讨论了饿汉模式在并发环境下的问题及解决方案,包括使用`synchronized`关键字和`volatile`修饰符来保证线程安全,同时对比了不同实现的效率差异。
摘要由CSDN通过智能技术生成

1.饱汉模式

package com.jva.util.design.single;

/**
 * 饱汉模式
 *
 * @author chengpingjia
 * @since 2023/4/26 11:41
 */
public class Full {

    private static final Full single = new Full();

    private Full() {
    }

    private static Full getSingle() {
        return single;
    }

}

2.1饿汉模式

package com.jva.util.design.single;

import cn.hutool.core.collection.ConcurrentHashSet;

import java.util.Set;
import java.util.concurrent.*;
import java.util.stream.IntStream;

/**
 * 饿汉模式
 *
 * @author chou
 * @since 2023/4/26 11:41
 */
public class Hunger {
    private static Hunger single = null;

    /**
     * 私有构造方法避免实例化
     */
    private Hunger() {
    }

    /**
     * 饿汉模式在使用的时候再去创建对象
     * 问题:在并发情况下可能有创建多个对象的可能
     *
     * @return
     */
    private static Hunger getSingle() {
        if (single == null) {
            single = new Hunger();
        }
        return single;
    }

    /**
     * 通过添加sync解决并发情况下创建多个对象的问题
     * 问题: sync包住了创建代码,效率比较低
     *
     * @return
     */
    private static synchronized Hunger getSingle2() {
        if (single == null) {
            single = new Hunger();
        }
        return single;
    }

    /**
     * 通过添加sync解决并发情况下创建多个对象的问题
     * 问题: sync包住了创建代码,效率比较低
     *
     * @return
     */
    private static Hunger getSingle3() {
        if (single == null) {
            synchronized (Hunger.class){
                if (single == null) {
                    single = new Hunger();
                }
            }
        }
        return single;
    }

    public static void main(String[] args) throws Exception {
//        ThreadPoolExecutor threadPoolExecutor = ThreadUtil.newExecutor(50, 10);
        Set<Integer> hashSet = new ConcurrentHashSet<>();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(50, 100, 2L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
        int size = 100;
        CountDownLatch countDownLatch = new CountDownLatch(size);
        IntStream.range(0,size).forEach(i->{
            Future<Integer> future = threadPoolExecutor.submit(() -> {
                try {
                    int hashCode = Hunger.getSingle().hashCode();

                    int hashCode2 = Hunger.getSingle2().hashCode();
                    int hashCode3 = Hunger.getSingle3().hashCode();
                    hashSet.add(hashCode3);
                    return hashCode;
                } finally {
                    countDownLatch.countDown();
                }
            });
        });

        countDownLatch.await();
        // 等待线程执行完成
        hashSet.forEach(System.out::println);
    }
}

2.2饿汉模式优化版

package com.jva.util.design.single;

/**
 * 饱汉模式
 *
 * @author chengpingjia
 * @since 2023/4/26 11:41
 */
public class HungerComplete {

    /**
     * volatile 的作用是保证内存可见性和防止指令重排
     * 这里的作用是防止指令重排,首先创建对象分为三步,1分配内存空间,2初始化(调用构造方法)3内存空间指向初始化(对象已经不等于null了)
     * 如果指令重排了代码执行顺序为 1,3,2
     * 如果第一个线程在初始化对象执行了3,第二个线程执行时发现对象不为null,拿去使用(由于第二步还没有执行)这个时候会报错
     *
     */
    private static volatile HungerComplete single = null;

    private HungerComplete() {
    }

    /**
     * 通过添加sync解决并发情况下创建多个对象的问题
     * 问题: sync包住了创建代码,效率比较低
     *
     * @return
     */
    private static HungerComplete getSingle3() {
        if (single == null) {
            synchronized (HungerComplete.class){
                if (single == null) {
                    single = new HungerComplete();
                }
            }
        }
        return single;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值