创建型模式之单例模式(2.1)
单例模式定义
在软件系统中,一个类只有一个实例对象。(该类只提供一个取得实例的静态方法)
推荐使用的三种单例模式
- DoubleCheck
- 静态内部类
- 枚举
1.DoubleCheck 双重检查
特点:效率高,线程安全,延迟加载。
class DoubleCheck
{
private static volatile DoubleCheck instance;
private DoubleCheck(){}
public static DoubleCheck getInstance()
{
/*
DoubleCheck如何实现?线程安全和效率提升
在多线程的环境下,假设线程A直接进入#2,实例化对象。
且实例化方法外用synchronized修饰,所以是线程安全的。
当线程A实例化对象结束,对象instance已经被创建,执行到#1的线程将会直接调到#3,返回instance
且DoubleCheck实现了延迟加载(new在方法里)
*/
if(instance==null) //#1
{
synchronized (DoubleCheck.class) //#2
{
if(instance==null)
{
instance = new DoubleCheck(); //#3
}
}
}
return instance;
}
}
public class Operation
{
public static void main(String[] args) {
DoubleCheck doubleCheck1 = DoubleCheck.getInstance();
DoubleCheck doubleCheck2 = DoubleCheck.getInstance();
System.out.println(doubleCheck1.hashCode());
System.out.println(doubleCheck2.hashCode());
}
}
2.静态内部类
特点:通过JVM类加载避免了线程安全问题,延迟加载,效率高。
class StaticClassInner {
private StaticClassInner() {}
/*
使用静态内部类,实现了延迟加载
调用getInstance()方法时,才会加载StaticClassInnerInstance。
通过JVM类加载线程安全的机制,避免了线程不安全。
*/
private static class StaticClassInnerInstance {
private static final StaticClassInner INSTANCE = new StaticClassInner();
}
public static StaticClassInner getInstance() {
return StaticClassInnerInstance.INSTANCE;
}
}
public class Operation
{
public static void main(String[] args) {
StaticClassInner doubleCheck1 = StaticClassInner.getInstance();
StaticClassInner doubleCheck2 = StaticClassInner.getInstance();
System.out.println(doubleCheck1.hashCode());
System.out.println(doubleCheck2.hashCode());
}
}
3.枚举
Effective Java作者Josh Bloch推荐。
enum Hq
{
INSTANCE;
public void printf()
{
System.out.println("ins");
}
}
public class Operation
{
public static void main(String[] args) {
Hq hq = Hq.INSTANCE;
Hq hqq = Hq.INSTANCE;
System.out.println(hq.hashCode());
System.out.println(hqq.hashCode());
}
}
饿汉式的延迟加载问题(可用)
如果创建的对象一定会被使用,那么可以忽略内存浪费的问题。
class SingleTom
{
private SingleTom()
{ }
/*
在静态常量中实例化对象,无法实现延迟加载,如果对象未被使用,会造成内存浪费。(#1)
无线程安全问题
将实例化对象放于静态代码块中并无实际作用
*/
private final static SingleTom instance; // = new SingleTom();#1
static //#2
{
instance=new SingleTom();
}
public static SingleTom getInstance()
{
return instance;
}
}
public class Operation
{
public static void main(String[] args) {
SingleTom hq = SingleTom.getInstance();
SingleTom hqq = SingleTom.getInstance();
System.out.println(hq.hashCode());
System.out.println(hqq.hashCode());
}
}
懒汉式的线程安全问题(不可用)
class Singletom {
private static Singletom singleton;
private Singletom() {}
/*
线程不安全:
调用getInsyance()方法时,如果同时有多个线程同时进入到#1
就会创建多个实例对象
倘若在方法上加上syn关键字,线程同步问题解决,但效率大大降低
doublecheck大概就是在这种纠结下选择用两次if(singleton == null)来控制线程同步和效率问题
*/
public static /*synchronized*/ Singletom getInstance() {
if (singleton == null) { //#1
singleton = new Singletom();
}
return singleton;
}
}
public class Operation
{
public static void main(String[] args) {
Singletom hq = Singletom.getInstance();
Singletom hqq = Singletom.getInstance();
System.out.println(hq.hashCode());
System.out.println(hqq.hashCode());
}
}
参考文档:
版权声明:本文为noneplus原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。