设计模式-单例模式

Posted yintingting

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-单例模式相关的知识,希望对你有一定的参考价值。

定义

单例模式 : 确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。

应用场景

J2EE标准中,ServletContextServletContextConfig等。

spring中的AppliationContext

数据库的连接池

。。。。

实现方式

(1)饿汉式

特点:在类加载的时候就立即创建单例对象。绝对线程安全,因为在线程还未出现前就实例化了,不可能出现访问安全问题。

优点:没有加任何的锁,执行效率高,用户体验好

缺点:类加载的时候就初始化,不管是否使用到都占着空间,可能会造成内存浪费

例子:spring IOC容器ApplicationContext就是典型的饿汉式单例。

方式一:

public class HungrySingleton {
//先静态、后动态
//先属性、后方法
//先上后下
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}

方式二:

//饿汉式静态块单例
public class HungryStaticSingleton {
private static final HungryStaticSingleton hungrySingleton;
static {
hungrySingleton = new HungryStaticSingleton();
}
private HungryStaticSingleton(){}
public static HungryStaticSingleton getInstance(){
return hungrySingleton;
}
}

(2)懒汉式

特点:被外部调用的时候才会实例化

 

//懒汉式单例
//在外部需要使用的时候才进行实例化
public class LazySimpleSingleton {
private LazySimpleSingleton(){}
//静态块,公共内存区域
private static LazySimpleSingleton lazy = null;
public static LazySimpleSingleton getInstance(){
if(lazy == null){
lazy = new LazySimpleSingleton();
}
return lazy;
}
}
public class ExectorThread implements Runnable{
@Override
public void run() {
LazySimpleSingleton singleton = LazySimpleSingleton.getInstance();
System.out.println(Thread.currentThread().getName() + ":" + singleton);
}
}
public class LazySimpleSingletonTest {
public static void main(String[] args) {
Thread t1 = new Thread(new ExectorThread());
Thread t2 = new Thread(new ExectorThread());
t1.start();
t2.start();
System.out.println("End");
}
}

运行结果:

技术图片

通过不断切换线程,并观测其内存状态,我们发现在线程环境下LazySimpleSingleton

被实例化了两次。有时,我们得到的运行结果可能是相同的两个对象,实际上是被后面

执行的线程覆盖了,我们看到了一个假象,线程安全隐患依旧存在。那么,我们如何来

优化代码,使得懒汉式单例在线程环境下安全呢?来看下面的代码,给getInstance()加

上synchronized 关键字,是这个方法变成线程同步方法:

public class LazySimpleSingleton {
private LazySimpleSingleton(){}
//静态块,公共内存区域
private static LazySimpleSingleton lazy = null;
public synchronized static LazySimpleSingleton getInstance(){
if(lazy == null){
lazy = new LazySimpleSingleton();
}
return lazy;
}
}

这时候,我们再来调试。当我们将其中一个线程执行并调用getInstance()方法时,另一

个线程在调用getInstance()方法,线程的状态由RUNNING 变成了MONITOR,出现阻

塞。直到第一个线程执行完,第二个线程才恢复RUNNING 状态继续调用getInstance()

方法。

以上是关于设计模式-单例模式的主要内容,如果未能解决你的问题,请参考以下文章

常用代码片段

性能比较好的单例写法

你熟悉的设计模式都有哪些?写出单例模式的实现代码

单例模式以及静态代码块

设计模式之单例模式

设计模式之单例模式