单例模式 rust和java的实现(一)https://developer.aliyun.com/article/1391996
2、懒汉式,线程安全
- 是否 Lazy 初始化:是
- 是否多线程安全:是
- 实现难度:易
- 描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
- 优点:第一次调用才初始化,避免内存浪费。
- 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
实例
public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
3、饿汉式
- 是否 Lazy 初始化:否
- 是否多线程安全:是
- 实现难度:易
- 描述:这种方式比较常用,但容易产生垃圾对象。
- 优点:没有加锁,执行效率会提高。
- 缺点:类加载时就初始化,浪费内存。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。
实例
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }
4、双检锁/双重校验锁(DCL,即 double-checked locking)
- 是否 Lazy 初始化:是
- 是否多线程安全:是
- 实现难度:较复杂
- 描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
实例
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
5、登记式/静态内部类
- 是否 Lazy 初始化:是
- 是否多线程安全:是
- 实现难度:一般
- 描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程,它跟第 3 种方式不同的是:第 3 种方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。这个时候,这种方式相比第 3 种方式就显得很合理。
实例
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }
6、枚举
- 是否 Lazy 初始化:否
- 是否多线程安全:是
- 实现难度:易
- 描述:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
实例
public enum Singleton { INSTANCE; public void whateverMethod() { } }
rust实现
在用rust进行懒加载时,最方便的还是用第三方库,本人运用的是lazy_static
库,在用这社区库时,需要引入在Cargo.toml文件下的[dependencies]
项目下引lazy_static = “1.4.0”。如图
use std::sync::{Arc, Mutex}; use lazy_static::lazy_static; struct Singleton; impl Singleton { //关联方法, 获取单例实例的方法 fn get_instance() -> Arc<Mutex<Singleton>> { // 使用懒加载创建单例实例 // 这里使用了 Arc 和 Mutex 来实现线程安全的单例 // 只有第一次调用 get_instance 时会创建实例,之后都会返回已创建的实例 static mut INSTANCE: Option<Arc<Mutex<Singleton>>> = None;//静态初始化,只运行一次 unsafe { // get_or_insert_with ,如果是 None ,则将从data计算的值插入选项中,然后返回对包含值的可变引用。 INSTANCE.get_or_insert_with(|| { Arc::new(Mutex::new(Singleton {}))}).clone() } } fn show_message(&self){ println!("Hello World!"); } } // 使用lazy_static的懒加载 struct SingletonL; impl SingletonL { fn show_message(&self){ println!("Hello World!"); } } lazy_static! { static ref INSTANCE: Mutex<SingletonL> = Mutex::new(SingletonL { }); } fn main() { // 获取单例实例,自定义 let instance1 = Singleton::get_instance(); // 修改单例数据 { let instance = instance1.lock().unwrap(); instance.show_message(); } // 获取单例实例,社区lazy_static let instance = INSTANCE.lock().unwrap(); instance.show_message(); }
rust代码仓库
https://github.com/onenewcode/design.git
本教程项目在bin文件夹下的singleobject.rs文件中