概念:
在Java应用程序中,一个类Class只有一个实例存在
运用:
1)系统资源,如文件路径,数据库链接,系统常量等
2)全局状态化类,类似AutomicInteger的使用
优缺点:
1)节省内存有利于垃圾回收
2)只能使用在特定的环境下,受限制于JVM和容器
单例作用范围的前提是在一个ClassLoad下。所以像分布式应用EJB就要用其它的方式来解决单例问题。
Demo:
分别列出多种实现方式,各分析其优缺点
1)静态成员直接初始化,或者在静态代码块初始化都可以
- class Singleton{
- private Singleton(){}
- private static final Singleton singleton = new Singleton();
- public static Singleton getInstance(){return singleton;}
- }
该实现只要在一个ClassLoad下就会提供一个对象的单例。但是美中不足的是,不管该资源是否被请求,它都会创建一个对象,占用jvm内存。从lazy initialization思想出发,出现了下2的写法
2)根据lazy initialization思想,使用到时才初始化。
- class Singleton{
- private Singleton(){}
- private static Singleton singleton ;
- public static synchronized Singleton getInstance(){
- if(singleton==null)
- singleton = new Singleton();
- return singleton;
- }
- }
该实现方法加了同步锁,可以有效防止多线程在执行getInstance方法得到2个对象。
缺点:只有在第一次调用的时候,才会出现生成2个对象,才必须要求同步。而一旦singleton 不为null,系统依旧花费同步锁开销,有点得不偿失。
因此再改进出现写法3
3)在2的基础上改进,改进标准:尽量减少锁资源(主要体现在执行时间,所占内存等)
- class Singleton{
- private Singleton(){}
- private static Singleton singleton ;
- public static Singleton getInstance(){
- if(singleton==null)//1
- synchronized(Singleton.class){//2
- singleton = new Singleton();//3
- }
- return singleton;
- }
- }
这种写法减少了锁开销,但是在如下情况,却创建了2个对象:
a:线程1执行到1挂起,线程1认为singleton为null
b:线程2执行到1挂起,线程2认为singleton为null
c:线程1被唤醒执行synchronized块代码,走完创建了一个对象
d:线程2被唤醒执行synchronized块代码,走完创建了另一个对象
所以看出这种写法,并不完美。
4)为了解决3存在的问题,引入双重检查锁定
- public static Singleton getInstance(){
- if(singleton==null)//1
- synchronized(Singleton.class){//2
- if(singleton==null)//3
- singleton = new Singleton();//4
- }
- return singleton;
- }
在同步锁代码块内部,再判断一次对象是否为null,为null才创建对象。这种写法已经接近完美:
a:线程1执行到1,已经进入synchronized的时候,线程挂起,线程1占有Singleton.class资源锁;
b:线程2执行到1,当它准备synchronized块时,因为Singleton.class被占用,线程2阻塞;
c:线程1被唤醒,判断出对象为null,执行完创建一个对象
d:线程2被唤醒,判断出对象不为null,不执行创建语句
如此分析,发现似乎没问题。
但是实际上并不能保证它在单处理器或多处理器上正确运行;
问题就出现在singleton = new Singleton()这一行代码。它可以简单的分成如下三个步骤:
mem= singleton();//1
instance = mem;//2
ctorSingleton(instance);//3
这行代码先在内存开辟空间,赋给singleton的引用,然后执行new 初始化数据,但是注意初始化是要消耗时间。如果此时线程3在执行步骤1的时候,发现singleton 为非null,就直接返回,那么线程3返回的其实是一个没构造完成的对象。
我们期望1,2,3 按照反序执行,但是实际jvm内存模型,并没有明确的有序指定。
这归咎于java的平台的内存模型允许“无序写入”。
5)在4的基础上引入volatile
代码如下:
- class Singleton{
- private Singleton(){}
- private static volatile Singleton singleton ;
- public static Singleton getInstance(){
- if(singleton==null)//1
- synchronized(Singleton.class){//2
- if(singleton==null)//3
- singleton = new Singleton();
- }
- return singleton;
- }
- }
Volatile 变量具有 synchronized
的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。
而volatile使用时有明确的规定:
- 对变量的写操作不依赖于当前值;
- 该变量没有包含在具有其他变量的不变式中;
—— 只有在状态真正独立于程序内其他内容时才能使用 volatile。
但是5的写法,虽然理论上似乎可以解决无序写入问题。实际上并非如此。
(我个人觉得这里对volatile语法说的不够详细,想知道详细的可以看这篇转帖Java 理论与实践: 正确使用 Volatile 变量 )
小结:
1)使用同步锁方法,内部锁存在不安全。
2)静态成员直接初始化。
相关推荐
### Java的Singleton模式详解 #### 一、Singleton模式概述 Singleton模式是一种常用的设计模式,在Java中主要用于确保一个类只有一个实例,并提供一个全局访问点。这种模式对于管理共享资源(如数据库连接池、...
Java2编程详解是一个专注于Java编程语言的深入教程,适用于不同经验水平的程序员。从初级开发到高级开发,本书旨在为读者提供全面的知识体系,帮助他们不仅学习Java的基础知识,更能够掌握并应用多种常用的开发模式...
在Java中,可以使用双重检查锁定(DCL)、枚举和静态内部类等方式实现。单例模式常用于配置中心、缓存管理等场景。 2. **工厂模式(Factory Method)**:定义一个创建对象的接口,但让子类决定实例化哪一个类。工厂...
为了保证线程安全,通常使用`synchronized`关键字对方法进行同步,但这样会降低性能。代码如下: ```java public class Singleton { private static Singleton INSTANCE; private Singleton() {} public ...
Java设计模式详解涉及到23种设计模式,这些设计模式可以根据其目的和范围被划分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)和行为型模式(Behavioral Patterns)。下面将详细...
在Java编程中,有23种经典的GoF(Gang of Four)设计模式,它们被分为三大类:创建型、结构型和行为型。本资源集合了这些模式的详细解释与源码分析,旨在帮助开发者深入理解和应用设计模式。 1. 创建型模式...
1. 创建型模式:如单例模式(Singleton)、工厂模式(Factory Method)和抽象工厂模式(Abstract Factory),主要关注对象的创建过程,使得代码更易于管理和测试。 2. 结构型模式:如适配器模式(Adapter)、装饰器...
在Java中,可以使用双重检查锁定(Double-Checked Locking)或者静态内部类方式实现。 2. **工厂模式(Factory)**:定义一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法让类的实例化推迟到子类。 3. *...
设计模式是软件工程中的一种最佳实践,它是在特定上下文中解决常见问题的模板或蓝图。...在"java24种设计模式详解"这个资源中,你会找到每种模式的详细讲解和实例,这将有助于你深入理解并掌握它们。
创建型模式如单例(Singleton)、工厂方法(Factory Method)和抽象工厂(Abstract Factory),主要关注对象的创建过程,确保在适当的时间以适当的方式创建对象。结构型模式如适配器(Adapter)、装饰器(Decorator...
### Java设计模式详解 #### 1. 创建型模式 创建型模式主要关注的是对象的创建方式,它们提供了创建对象的最佳方法。以下是对几种常见的创建型模式的深入解析: ##### 1.1.1 工厂方法(Factory Method) **定义**...
在Java编程语言中,枚举(enum)是一种特殊的类,用于定义一组固定的常量。它在许多场景下比使用常量或int类型的硬编码值更安全、更具可读性。本篇文章将深入探讨Java枚举的特性、用法以及如何在实际开发中充分利用...
Java 中 23 种设计模式详解 在软件设计中,设计模式是解决特定问题的通用解决方案。 Java 中有 23 种常见的设计模式,下面将对每种设计模式进行详细的解释: 1. 抽象工厂模式(Abstract Factory) 抽象工厂模式...
Java设计模式-单例模式详解 单例模式是 Java 设计模式中的一种常用的设计模式,旨在保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例模式的目的是为了保证在一个进程中,某个类有且仅有一个实例。 ...
### Java软件开发实战:Java基础与案例开发详解之Static修饰符 #### 6.5 Static修饰符 在Java中,`static`关键字用于声明与类而不是与实例相关的变量、方法或代码块。这一特性使得静态成员能够被类本身直接访问,...
### Singleton Pattern 单例模式应用详解 #### 一、单例模式概述 单例模式(Singleton Pattern)是一种常用的软件设计模式,在系统中确保某个类只有一个实例,并提供一个全局访问点。这种模式通常用于控制资源的...
Java单例模式详解 Java单例模式是Java编程中的一种设计模式,旨在保证一个类仅有一个实例,并提供一个全局访问点。下面我们将对9种Java单例模式进行详细的介绍。 首先,单例模式的特点是: 1. 一个类只允许产生...
**Singleton 模式详解** Singleton 是一种在软件工程中广泛使用的创建型设计模式,它的主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式常用于需要频繁实例化然后销毁的对象,或者当实例化一个...
在Java中,实现Singleton有许多方法,每种都有其优缺点。以下是五种常见的Singleton实现方法的详细解析: 1. **基本实现(非线程安全)** ```java public class Singleton1 { private static Singleton1 ...