我是靠谱客的博主 甜美蜡烛,最近开发中收集的这篇文章主要介绍单例模式详解,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

单例模式:一般是指在运行的JVM中只有一个实例存在。通过使用 private的构造函数确保了在一个应用中只能产生一个类的实例,

并且实例是在单例类Singleton中自己实例化的。

主要分为 懒汉模式和饿汉模式

两者结构:

均是 一个静态的实例[ 静态为类对象]

私有的构造方法。防止外部直接常见对象

静态方法:返回类中的静态实例对象


懒汉,饿汉主要是创建实例的时机不一样。

饿汉模式:是在类加载后就会对类的静态对象进行初始化。

private static final Singleton singleton = new Singleton();

//私有化构造函数
private Singleton() {
}
//给出一个公共的静态方法返回一个单一实例
public static Singleton getInstance() {
return singleton;
}

这个方法却牺牲了Lazy的特性。单例类加载的时候就实例化了。如注释所述:非懒加载,如果构造的单例很大,构造完又迟迟不使用,会导致资源浪费。

懒汉模式:是在方法调用的时候才会创建实例。

private static Singleton singleton;

//私有化构造函数
private Singleton() {
}
//给出一个公共的静态方法返回一个单一实例
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();

}
return singleton;
}




单例模式推荐的写法

private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}


static的成员变量只在类加载的时候初始化一次,且类加载是线程安全的。所以这个方法实现的单例是线程安全的。

内部类SingletonHolder只有在getInstance()方法第一次调用的时候才会被加载(实现了lazy),而且类的加载过程是线程安全的。内部类加载的时候实例化一次instance。全局也就一个单例


模拟多线程环境下。懒汉单例模式的缺陷,可能导致在jvm中产生多个实例。


public static void main(String[] args) throws Exception {
int num = 20;

final CyclicBarrier start = new CyclicBarrier(num);

final CountDownLatch end = new CountDownLatch(num);

final Set<String> set = Collections.synchronizedSet(new HashSet<String>());

ExecutorService executorService = Executors.newFixedThreadPool(num);

for (int i = 0; i < num; i++) {
executorService.execute(new SingletonRunnable(i, start, end, set));

}
end.await();

System.out.println("------并发情况下我们取到的实例------");

for (String instance : set) {
System.out.println(instance);

}
executorService.shutdown();

}
public static class SingletonRunnable implements Runnable {
private CountDownLatch countDownLatch;

private CyclicBarrier start;

private Integer id;

private Set<String> set;


SingletonRunnable(Integer id, CyclicBarrier start, CountDownLatch countDownLatch, Set<String> set) {
this.countDownLatch = countDownLatch;

this.start = start;

this.id = id;

this.set = set;

}
@Override

public void run() {
try {
System.out.println("准备构造------------" + id);

start.await();

System.out.println("开始构造" + id);

set.add(Singleton.getInstance().toString());

} catch (Exception e) {
}
countDownLatch.countDown();

}
}



与Spring容器的单例的区别:

一般的单例是指JVM中只有一个实例, spring 的单例是spirng 容器中只有一个实例。

Spring中说的单例是相对于容器的,既在ApplicationContext中是单例的。而平常说的单例是相对于JVM的。另一个JVM可以有多个Spring容器,而且Spring中的单例也只是按bean的id来区分的



最后

以上就是甜美蜡烛为你收集整理的单例模式详解的全部内容,希望文章能够帮你解决单例模式详解所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部