单例的几种写作方式和序列化

2015-09-02 16:02:07

推荐一篇大神的文章,好久之前就看过这篇文章,而且本文的思路就来自这篇文章~其实有了大牛的文章,本文可写可不写,但是为了给自己总结一下,就写了~

http://callmegod.iteye.com/blog/1474441

单例的作用想必大家都知道,也一直在用,但是到底怎样的单例是“比较”完美的单例模式呢?我也不知道,但是我一直在寻找答案~

下面我简单总结一下单例吧,否则太乱了

Part 1:单例的几种实现方式

1. 恶汉式:指在类加载或者被初始化的时候,就创建一个单例对象,有好几个变种

第一种:类加载时创建对象

1 public class SingletonObj {
2     public static final SingletonObj INSTANCE = new SingletonObj();
3
4     private SingletonObj() {}
5 }

第二种:类加载时创建对象,但是对象是私有的,只能通过static的方法获取,好像更加“面向对象”

1 public class SingletonObj {
2     private static final SingletonObj INSTANCE = new SingletonObj();
3
4     private SingletonObj() {}
5
6     public static SingletonObj getInstance() {
7         return INSTANCE;
8     }
9 }

第三种:类初始化的时候创建对象

 1 public class SingletonObj {
 2     public static SingletonObj INSTANCE;
 3
 4     static {
 5         INSTANCE = new SingletonObj();
 6     }
 7
 8     private SingletonObj() {}
 9
10     private static SingletonObj getInstance() {
11         return INSTANCE;
12     }
13 }

2. 懒汉式:使用时才创建对象,相比于恶汉式,这种方式会延迟加载。

第一种:线程不安全

 1 public class SingletonObj {
 2     public static SingletonObj INSTANCE;
 3
 4     private SingletonObj() {}
 5
 6     private static SingletonObj getInstance() {
 7         if (INSTANCE == null) {
 8             INSTANCE = new SingletonObj();
 9         }
10         return INSTANCE;
11     }
12 }

第二种:线程安全,同时支持双重检查机制,这种也是最常见的单例模式(这种方式不推荐)

 1 public class SingletonObj {
 2     private static final Object sLocker = new Object();
 3     public static SingletonObj INSTANCE;
 4
 5     private SingletonObj() {
 6     }
 7
 8     private static SingletonObj getInstance() {
 9         if (INSTANCE == null) {
10             synchronized (sLocker) {
11                 if (INSTANCE == null) {
12                     INSTANCE = new SingletonObj();
13                 }
14             }
15         }
16         return INSTANCE;
17     }
18 }

这种方式有自己的弊端:有种说法,说是jdk1.5后才能保证达到单例效果,但是据我所知,这种方式来自C语音的双重检查机制,在Java中不见得能完全适用。

所以保险的加锁方式如下:

 1 public class SingletonObj {
 2     public static SingletonObj INSTANCE;
 3
 4     private SingletonObj() {
 5     }
 6
 7     private synchronized static SingletonObj getInstance() {
 8         if (INSTANCE == null) {
 9             INSTANCE = new SingletonObj();
10         }
11         return INSTANCE;
12     }
13 }

3. 静态内部类方式:加锁的方式能做到线程安全,但是加锁会导致效率比较低,而这种方式既能满足线程安全的要求,而且效率比较高

 1 public class SingletonObj {
 2     private static class SingletonHolder {
 3         public static final SingletonObj INSTANCE = new SingletonObj();
 4     }
 5
 6     private SingletonObj() {
 7     }
 8
 9     private static SingletonObj getInstance() {
10         return SingletonHolder.INSTANCE;
11     }
12 }

主要利用到静态类只会被JVM加载一次的特性~所以即便是多线程,也不会产生两个对象。这也是一种比较优雅的方式。

4. 《Effective Java》中提到一种更好的方法:单元素的枚举类型,大体实现如下(极棒的方式)

 1 public enum SingletonEnum {
 2     INTANCE(12, "Niu");
 3
 4     private int age;
 5     private String name;
 6     SingletonEnum(int age, String name) {
 7         this.age = age;
 8         this.name = name;
 9     }
10
11     public void doSomething() {
12         System.out.println("SingletonEnum doSomething");
13     }
14 }

好处:线程安全,序列化/反序列化安全

弊端:失去了类的一些特性,因此不够流行

Part 2:

1. 上面提到了序列化,我们都知道,所谓序列化/反序列化就是对象和流之间的一种转换方式。因为对象是不能直接保存在硬盘或者通过网络传输的,但是序列化成流之后,原则上你想干嘛都行。但是单例的序列化比较特殊,我们知道,单例的作用就是保证JVM中只有一个对象,那么如何保证反序列化后的对象和序列化之前的是同一个对象呢?

 1 public class SingletonCase implements Serializable {
 2     private static class SingltonHolder {
 3         public static final SingletonCase INSTANCE = new SingletonCase();
 4     }
 5
 6     private int age;
 7     private String name;
 8     public static SingletonCase getInstance() {
 9         return SingltonHolder.INSTANCE;
10     }
11
12     private SingletonCase() {
13         age = 133;
14         name = "David";
15     }
16
17     public int getAge() {
18         return age;
19     }
20
21     public String getName() {
22         return name;
23     }
24
25     private Object readResolve() {
26         return SingltonHolder.INSTANCE;
27     }
28 }

需要添加如上绿色代码,这是一个方法,返回值必须是Object,而不能是自己定义的对象。这个方法的作用是:每次反序列化完成前都会去调用readResolve()方法,将用原对象取代新创建出来的对象,这样就保证了序列化前后对象的唯一性。

单例的线程安全和序列化一直是个比较难缠的安全问题,所以单元素的枚举类型实现单例,既能保证线程安全性,又能保证序列化安全,可谓是一种perfect的方案~~

2. 关于transient

如果你不想某个成员变量被序列化,那么就可以用这个关键字来修饰~具体的使用大家问度娘。

时间: 2024-11-04 02:28:23

单例的几种写作方式和序列化的相关文章

单例的2种使用方式

一直都对设计模式,限于书本的理论知识,今天终于用到了众多设计模式中的一种,单例模式. 一共有2种使用方法.第一种是用它里面的函数,第二种是用它里面的变量. 上代码: 第一种,用里面的函数. 单例.h @interface NetManager : NSObject + (id)sharedManager; -(void)firstPrintf; -(void)secondPrintf; -(void)threeprintf; -(void)fourprintf; @end 单例.m static

IOS单例的两种实现方式

单例模式算是开发中比较常见的一种模式了.在iOS中,单例有两种实现方式(至少我目前只发现两种). 根据线程安全的实现来区分,一种是使用@synchronized ,另一种是使用GCD的dispatch_once函数. [email protected]synchronized 实现 static InstanceClass *instance; + (InstanceClass *)defaultInstance{ @synchronized (self){ if (instance == ni

iOS开发之——单例的几种设计方式

单例是ios开发中常用的一种设计模式,通常用来控制器之间传值.方便.高效,全局通用. 单例模式的设计分为ARC和MRC. ARC: 方式一 1.创建一个继承自NSObject的类. 2.在这个类的.h文件中声明类方法: + (instancetype)sharedInstance; 2.在这个类的.m文件中实现以下方法: static id instance; + (instancetype)sharedInstance { static dispatch_once_t onceToken; d

单例的三种实现方式

1双重加锁模式 public class Singleton { private volatile static Singleton singleton; public static Singleton getSingleton(){ if(singleton==null){ synchronized (Singleton.class) { if(singleton==null){ singleton = new Singleton(); } } } return singleton; } pr

iOS中创建单例的两种方式

刚刚开始做iOS开发的时候,不知道怎么创建单例,在网上搜的也大多数都不太全,所以总结了一下创建单例的两种方式 首先在.h文件中声明类方法 1 +(instancetype)sharedUtils; 然后在.m文件中实现它,实现的方法有两种 第一种,在创建一个对象时先判断在程序中有没有创建过这个对象 1 static PublicUtils *DefaultManager = nil; 2 3 +(instancetype)sharedUtils 4 { 5 if (!DefaultManager

java单例设计模式八种方式

单例设计模式介绍 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法). 比如Hibernate的SessionFactory,它充当数据存储源的代理,并负责创建Session对象.SessionFactory并不是轻量级的,一般情况下,一个项目通常只需要一个SessionFactory就够,这是就会使用到单例模式. 单例设计模式八种方式 单例模式有八种方式: 饿汉式( ( 静态常 量) ) 饿汉式(静态

[💯原]IOS之Objectic-C的单例的两种安全实现方案

所有转出博客园,请您注明出处:http://www.cnblogs.com/xiaobajiu/p/4122034.html Objectic-C的单例的两种安全实现方案 首先应该知道单例的实现有两大类,一个是懒汉式,一个是饿汉式.所谓的懒汉式就是在我们用到某对象(资源)的时候,去问一个负责提供的方法要那个对象.那个方法发现没有这个资源时就去创建资源,如果是已经有该资源时就直接返回这个资源.而饿汉式就是那个负责提供的方法早已为我们准备好了我们想要的资源问它,它就提供给我们那个它早就准备好了的资源

浅谈单例的三种实现--C#

传统的double check : public sealed class Singleton { private static Singleton instance = null; private static readonly object padlock = new object(); Singleton() { } public static Singleton Instance { get { if (instance == null) { lock (padlock) { if (i

Python单例的一种简单写法

最原始的想法就是每个类都重写new方法. class Dog: dog = None def __new__(cls, *args, **kwargs): if cls.dog is None: cls.dog = object.__new__(cls) print('create singleton over') return cls.dog def __init__(self, name): print('init is called') self.name = name # 下面这句话会报