/**
* @ClassName SingleTon
* @Author 潘忆慈
* @Computer DELL G7
* @Date 2018/11/3 9:38
* @Version 1.0
* @Discription TODO
* @注释: 单例设计模式(Singleton Pattern):
*
* 摘要: 保证一个类只有一个实例,并创建一个能访问他的全局访问点
*
* 单例模式三要素:
* 1.单例类只能有一个实例 (需考虑被反射破坏,序列化/反序列化,对象垃圾回收)
* 2.单例类必须自己创建唯一的实例(private修饰)
* 3.单例类必须给所有其他对象提供这一个实例(静态方法getInstance()返回)
*
* 优点:
* 1.提供了唯一的实例受控访问,避免对资源的多重占用
* 2.内存里只有一个实例,减少了内存开销
* 缺点:
* 1.单例模式中没有抽象层,因此扩展很是问题
* 2.一定程度上违反了“单一职责原则”
* 随笔:
* 如果我们不将这个类控制成单例的结构,应用中就会存在很多一模一样的类实例
* 这会非常浪费系统的内存资源,而且容易导致错误甚至一定会产生错误
* 所以我们单例模式所期待的目标或者说使用它的目的,是为了尽可能的节约内存空间
* 减少无谓的GC消耗,并且使应用可以正常运作。
*
* 如何判断一个类是否要做成单例?
* 最简单的区别就是"这个类在应用中有两个或者两个以上的实例会引起错误,
* 又或者这个类在整个运行时刻中只允许有一种状态"。
* 经典应用场景:
* 缓存、日志、配置文件、线程池.....
*
* 单例模式的六种代码实现方式:
* 1.饿汉模式 (简单)
* 2.懒汉模式 (线程不安全)
* 3.同步懒汉模式 (同步方法效率低)
* 4.双重校验锁模式 (可用)
* 5.静态内部类模式 (较为推荐)
* 6.枚举模式 (黄书推荐(Effective JAVA)不常见)
*
**/
public class SingleTon {
public static void main(String[] args) {
//懒汉模式
LazyManSingleTon.getInstance();
//饿汉模式
HungryManSingleTon.getInstance();
//同步饿汉模式
SyLazyManSingleTon.getInstance();
//双重校验锁模式
DoubleLockSingleTon.getInstance();
//静态内部类模式
StaticSingleTon.getInstance();
//枚举模式
//EasySingleton.INSTANCE;
//测试案例
TestSingleTon testSingleTon_1 = TestSingleTon.getSingleTon();
System.out.println(testSingleTon_1.getData()); //打印结果 0
testSingleTon_1.setData(99);
System.out.println(testSingleTon_1.getData()); //打印结果99
TestSingleTon testSingleTon_2 = TestSingleTon.getSingleTon();
System.out.println(testSingleTon_2.getData()); //打印结果99
}
}
//———————————————————————饿汉模式————————————————————————
/**
* 饿汉模式
* Lazy 不初始化
* 多线程 安全
*
* 优点: 没有加锁执行效率高,
* 缺点: 没有Lazy初始化,可能有时候不需要使用,浪费内存
*/
class HungryManSingleTon{
//静态实例变量,直接初始化
private static SingleTon instance = new SingleTon();
//私有化构造器
private HungryManSingleTon(){}
//静态public方法,向整个业务提供单例获取方式
public static SingleTon getInstance(){
return instance;
}
}
//———————————————————————懒汉模式————————————————————————
/**
* 懒汉模式
* Lazy 会初始化
* 多线程 不安全
*
* 特点:
* 能够在调用getInstance()时再创建对象,所以称为懒汉式。不调用不创建,而上文的饿汉模式会直接创建
* 这种实现最大的问题就是不支持多线程。因为没有加锁同步。
*/
class LazyManSingleTon{
//静态实例变量, 但不初始化
private static SingleTon instance;
//私有化构造器
private LazyManSingleTon(){}
//提供全局的单例获取方式
public static SingleTon getInstance(){
//判断 instance 是否为空
if(instance == null){
//在这个地方 new 对象
instance = new SingleTon();
}
return instance;
}
}
//—————————————————————同步懒汉模式————————————————————————
/**
* 同步懒汉模式
* Lazy 会初始化
* 多线程 安全
*
* 特点:
* 使用synchronized来修饰,除第一次使用,后面getInstance()不需要同步;每次同步,效率很低。
* 效率很低!
*/
class SyLazyManSingleTon{
//静态实例变量, 但不初始化
private static SingleTon instance;
//私有化构造器
private SyLazyManSingleTon(){}
//提供全局的单例获取方式
public static synchronized SingleTon getInstance(){
//判断 instance 是否为空
if(instance == null){
//new一个SingleTon对象
instance = new SingleTon();
}
return instance;
}
}
//————————————————————双重校验锁模式————————————————————————
/**
* 双重校验锁
* Lazy 会初始化
* 多线程 安全
*
* 特点:
* 这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
* 实例变量需要加volatile 关键字保证易变可见性,JDK1.5起才可用
*/
class DoubleLockSingleTon{
// 静态实例变量,不是初始化,使用volati修饰
private static volatile SingleTon instance;
//私有化构造器
private DoubleLockSingleTon(){}
//提供全局的单例获取方式
public static SingleTon getInstance(){
if(instance == null){
synchronized (SingleTon.class){
if(instance == null){
instance = new SingleTon();
}
}
}
return instance;
}
}
//———————————————————静态内部类模式--———————————————————————
/**
* 静态内部类模式
* Lazy 会初始化
* 多线程 安全
*
* 特点:
* 同样利用了JVM类加载机制来保证初始化实例对象时只有一个线程,静态内部类SingletonHolder
* 类只有第一次调用 getInstance 方法时,才会装载从而实例化对象。
*/
class StaticSingleTon{
private static class SingletonHolder {
private static final SingleTon INSTANCE = new SingleTon();
}
private StaticSingleTon (){}
public static final SingleTon getInstance() {
return SingletonHolder.INSTANCE;
}
}
//———————————————————---枚举模式--———————————————————————
/**
* 枚举模式
* Lazy 不会初始化
* 多线程 安全
*
* 特点:
* 从Java1.5开始支持enum特性;无偿提供序列化机制,
* 绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候。
*
* 这种方法没有被广泛采用,而且让人生疏
* 但是! 这是单例模式的最佳实现方法
*/
/*public enum EnumSingleTon{
//定义一个枚举元素,代表Singleton实例
INSTANCE;
public void doSomethingMethod() {
}
}*/
/**
* 杨老师的实验案例
* 懒汉模式
*/
class TestSingleTon{
private int data;
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
private static TestSingleTon singleTon;
private TestSingleTon(){}
public static TestSingleTon getSingleTon(){
if(singleTon == null){
singleTon = new TestSingleTon();
}
return singleTon;
}
}
JAVA设计模式:单例模式
最新推荐文章于 2024-04-21 20:00:00 发布