您的位置:首页 > 编程语言 > Java开发

浅析Java设计模式 - 单例模式

2016-03-09 14:12 603 查看
以下是三种单例模式的代码实现,前两者用的比较多 (言外之意 最后一种可以忽略)

package com.signle;

import java.util.HashMap;
import java.util.Map;

/**
*
* @title 单例模式
* @Copyright Copyright (c)2016年3月9日
* @Company CTC
* @version 1.0
* @author ejokovic
* @time   上午11:21:53
* @package
* com.signle
*
*/
public class TestSignle {
public static void main(String[] args) {
Singleton s = Singleton.getInstance();
Singleton s1 = Singleton.getInstance();
//System.out.println(s==s1);
SigletionC singleC = SigletionC.getInstance(null);
System.out.println(singleC.about());
}

}

/**
* 懒汉式
*  是线程不安全的并发环境下很可能出现多个Singleton实例,要实现线程安全
* @title
* @Copyright Copyright (c)2016年3月9日
* @Company CTC
* @version 1.0
* @author ejokovic
* @time   上午11:23:44
* @package
* com.signle
*
*/
class Singleton{
private Singleton(){}
private static Singleton Singleton;
public static Singleton getInstance(){
if(Singleton==null){
Singleton = new Singleton();
}
return Singleton;
}
}

/**
* 解决懒汉式单例线程安全(一)
* 在getInstance方法上加同步锁
* @title
* @Copyright Copyright (c)2016年3月9日
* @Company CTC
* @version 1.0
* @author ejokovic
* @time   上午11:31:45
* @package
* com.signle
*
*/
class Singleton2{
private Singleton2(){}
private static Singleton2 Singleton;
public static synchronized  Singleton2 getInstance(){
if(Singleton==null){
Singleton = new Singleton2();
}
return Singleton;
}
}

/**
* 解决懒汉式单例线程安全(二)
* 双重检查锁定
* @title
* @Copyright Copyright (c)2016年3月9日
* @Company CTC
* @version 1.0
* @author ejokovic
* @time   上午11:34:42
* @package
* com.signle
*
*/
class Singleton3{
private Singleton3(){}
private static Singleton3 Singleton;
public static synchronized  Singleton3 getInstance(){
if(Singleton==null){
synchronized (Singleton3.class){
if(Singleton==null){
Singleton = new Singleton3();
}
}
}
return Singleton;
}
}

/**
* 解决懒汉式单例线程安全(二)
* 静态内部类
* 这种比上面1、2都好一些,既实现了线程安全,又避免了同步带来的性能影响。
* @title
* @Copyright Copyright (c)2016年3月9日
* @Company CTC
* @version 1.0
* @author ejokovic
* @time   下午12:06:54
* @package
* com.signle
*
*/
class Singleton4{
private static class LazyHolder{
private static final Singleton4 INSTANCE = new Singleton4();
}
private Singleton4(){}
public static synchronized  Singleton4 getInstance(){
return LazyHolder.INSTANCE;
}
}

/**
* 饿汉式单例类.在类初始化时,已经自行实例化
* @title
* @Copyright Copyright (c)2016年3月9日
* @Company CTC
* @version 1.0
* @author ejokovic
* @time   下午12:12:23
* @package
* com.signle
*
*/
class SigletionA{
private SigletionA(){}
private static final SigletionA sigletionA = new SigletionA();
public static SigletionA getInstance(){
return sigletionA;
}
}

//登记式单例
class SigletionC{
private static Map<String,SigletionC> map = new HashMap<String,SigletionC>();
static{
SigletionC single = new SigletionC();
map.put(single.getClass().getName(), single);
}
//保护的默认构造子
protected SigletionC(){}
//静态工厂方法,返还此类惟一的实例
public static SigletionC getInstance(String name) {
if(name == null) {
name = SigletionC.class.getName();
System.out.println("name == null"+"--->name="+name);
}
if(map.get(name) == null) {
try {
map.put(name, (SigletionC) Class.forName(name).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return map.get(name);
}
//一个示意性的商业方法
public String about() {
return "Hello, I am RegSingleton.";
}
}


单例模式

在了解饿汉与懒汉的区别前 先了解下什么是线程安全:

假如你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时执行这段代码,如果每次执行的结果和单线程中执行的结果一致 且 其它变量的值也和预期的一致 这就是线程安全

换句话说:

一个类或者程序提供的接口对于线程来说是原子操作,或者多个线程之间切换不会导致该接口的执行结果存在差异性 也就是说我们不用考虑同步的问题 那就是线程安全的

饿汉式和懒汉式区别:

从名字上来说,饿汉和懒汉:

  饿汉是当类加载时就把单例初始化完成,保证getInstance的时候,单例是已经存在的了

  而懒汉比较懒,只有当调用getInstance的时候,才会去初始化这个单例;

从线程是否安全角度讲:

  饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题

  懒汉式本身是非线程安全的,为了实现线程安全有几种写法,分别是上面的1、2、3,这三种实现在资源加载和性能方面有些区别;

从资源加载和性能的角度讲:

    饿汉式在类加载的同时就实例化一个静态对象出来,不管之后是否用到这个静态对象,都会占据一定的内存,但是相应的 在第一次调用时的速度也会更快,因为资源已经初始化好了;

    至于以上1,2,3 这三种实现又有些区别

    第一种,在方法调用上加了同步,虽然线程安全了,但每次都要同步,会影响性能,毕竟大部分的情况下是不需要同步的

    第二种,在getInstance方法中做了两次null检查,确保了只有第一次调用该静态对象的时候才会同步,这样也是线程安全的,同时避免了每次调用时的同步损耗;

    第三种,利用了classloader机制,保证初始化instance时只有一个线程 所以是线程安全的 同时没有性能损耗
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: