c# ioc 单例模式_单例模式(Singleton)

一句话总结

保证独一无二

实质

一个类只有一个实例

三步骤

1 私有的构造函数

2 私有的的成员变量:记录这个单实例

3 公有的getter函数:没有实例时创建它;已有实例则返回该实例

场景

配置文件,IOC容器,日历,监控系统

技术方案:

1 饿汉式:在加载类时创建单例对象,优点:绝对的线程安全,缺点:浪费内存

public class Hungry {

private Hungry(){}

/**

* 类加载顺序:

* 先静态、后动态

* 先属性、后方法

* 先上后下

*/

private static final Hungry hungry = new Hungry();

public static Hungry getInstance(){

return hungry;

}

}

/**

* 测试线程安全

*/

public class ThreadSafeTest {

public static void main(String[] args) {

int count = 200;

CountDownLatch latch = new CountDownLatch(count);

long start = System.currentTimeMillis();

for (int i = 0; i < count;i ++) {

new Thread(){

@Override

public void run() {

try{

try {

latch.await();

}catch(Exception e){

e.printStackTrace();

}

Object obj = LazyOne.getInstance();

System.out.println(System.currentTimeMillis() + ":" + obj);

}catch (Exception e){

e.printStackTrace();

}

}

}.start();

latch.countDown();

}

long end = System.currentTimeMillis();

System.out.println("总耗时:" + (end - start));

}

}

2 懒汉式:在第一次调用时实现,为了保证线程安全,有以下两种实现方式

2.1 通过synchronized加锁实现,缺点是耗时长

/**

* 通过synchronized保证线程安全

*/

public class LazyTwo {

private LazyTwo(){}

private static LazyTwo lazy = null;

public static synchronized LazyTwo getInstance(){

if(lazy == null){

lazy = new LazyTwo();

}

return lazy;

}

}

2.2 通过内部类实现,目前最优秀的实现单例的方式

/**

* 通过内部类实现单例,解决了饿汉式的内存浪费和synchronized的性能

*/

public class LazyThree {

private boolean initialized = false;

//默认使用LazyThree的时候,会先初始化内部类

//如果没使用的话,内部类是不加载的

private LazyThree(){

synchronized (LazyThree.class){//解决通过反射来创建单例,一般不需要考虑

if(initialized == false){

initialized = !initialized;

}else{

throw new RuntimeException("单例已被侵犯");

}

}

}

public static final LazyThree getInstance(){

//在返回结果以前,一定会先加载内部类

return LazyHolder.LAZY;

}

//默认不加载

private static class LazyHolder{

private static final LazyThree LAZY = new LazyThree();

}

}

3 注册登记式:spring使用的方式,下面的例子存在线程安全

//Spring中的做法,就是用这种注册式单例

public class BeanFactory {

private BeanFactory(){}

//线程安全

private static Map ioc = new ConcurrentHashMap();

public static Object getBean(String className){

if(!ioc.containsKey(className)){

Object obj = null;

try {

obj = Class.forName(className).newInstance();

ioc.put(className,obj);

} catch (Exception e) {

e.printStackTrace();

}

return obj;

}else{

return ioc.get(className);

}

}

}

4 枚举式:枚举的实质是继承Enum的类,枚举元素是类中的常量,所有可以保证线程安全。

public enum RegiterEnum {

INSTANCE,BLACK,WHITE;

public void getInstance(){}

}

5 序列化和反序列化保证单例:通过重写readResolve()来实现

public class Seriable implements Serializable {

public final static Seriable INSTANCE = new Seriable();

private Seriable(){}

public static Seriable getInstance(){

return INSTANCE;

}

/**

* 重写此方法是为了解决反序列化默认创建对象

*/

private Object readResolve(){

return INSTANCE;

}

}

/**

* 单例方法的测试类

*/

public class SeriableTest {

public static void main(String[] args) {

Seriable s1 = null;

Seriable s2 = Seriable.getInstance();

FileOutputStream fos = null;

try {

fos = new FileOutputStream("Seriable.obj");

ObjectOutputStream oos = new ObjectOutputStream(fos);

oos.writeObject(s2);

oos.flush();

oos.close();

FileInputStream fis = new FileInputStream("Seriable.obj");

ObjectInputStream ois = new ObjectInputStream(fis);

s1 = (Seriable)ois.readObject();

ois.close();

System.out.println(s1 == s2);//true

} catch (Exception e) {

e.printStackTrace();

}

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值