Java单例类的简单实现
对于java新手来说,单例类给我的印象挺深,之前一道web后台笔试题就是写单例类。*.*可惜当时不了解。
在大部分时候,我们将类的构造器定义成public访问权限,允许任何类自由创建该类的对象。但在某些时候,允许其他类自由创建该类的对象没有任何意义,还可能造成系统性能下降(因为频繁地创建对象、回收对象带来的系统开销问题)。例如,系统可能只有一个窗口管理器、一个假脱机打印设备或一个数据库引擎访问点,此时如果在系统中为这些类创建多个对象就没有太大的实际意义。因此,在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。
Java单例类有以下特点:
1、单例类始终只能创建一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
实现要求:
1、类的构造器使用private修饰,隐藏该类的所有构造器;
2、根据良好封装原则,提供public方法作为该类的访问点,用于创建该类的对象,且该方法必须使用static修饰;
3、类必须缓存已经创建的对象,故需要一个static修饰的成员变量。
先看一个单例类的经典实现:
class Singleton
{
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance()
{
if(instance == null)
instance = new Singleton();
return instance;
}
}
public class SingletonTest
{
public static void main(String[] args)
{
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
通过上面的getInstance()方法提供的自定义控制,保证Singleton类只能产生一个实例。(这也是封装的优势:不允许自由访问类的Field和实现细节,而是通过方法来提供访问接口)所以在SingletonTest类的main方法中,看到两次产生的Singleton对象实际上是同一个对象,程序输出“true”。
关于单例类的三种实现方式:饿汉式单例类、懒汉式单例类、登记式单例类(暂时还不懂*.*)
1.饿汉式单例类:立即创建实例
class Singleton1
{
//已经自行实例化
private static final Singleton1 instance = new Singleton1(); private Singleton1() {}
public static Singleton1 getInstance()
{
return instance;
}
}
2.懒汉式单例类:在第一次调用时实例化
class Singleton2
{
//注意,这里没有final
private static Singleton2 instance=null; private Singleton2() {}
public static Singleton2 getInstance()
{
if (instance == null)
instance = new Singleton2();
return instance;
}
}
但上面这段程序在多线程环境中是不能保证单个实例的。例如下表所示多线程可能情况:
| 时间点 | 线程1 | 线程2 | instance值 |
| 1 | 进入getInstance()方法 | null | |
| 2 | 进入getInstance()方法 | null | |
| 3 | 执行if(uniqueInstance == null)判断 | null | |
| 4 | 执行if(uniqueInstance == null)判断 | null | |
| 5 | 执行instance = new Singleton() | Singleton1 | |
| 6 | 执行instance = new Singleton() | Singleton2 | |
| 7 | 执行return instance; | Singleton1 | |
| 8 | 执行return instance; | Singleton2 |
因此,便有了多线程安全的懒汉式单例类实现:
class Singleton2
{
private static Singleton2 instance=null; private Singleton2() {}
public static synchronized Singleton2 getInstance()
{
if (instance == null)
instance = new Singleton2();
return instance;
}
}
因为通过给getInstance()方法增加synchronized关键字,也就是给getInstance()方法线程加锁,迫使每次只能有一个线程进入这个方法。但加锁的同步方法可能造成程序执行效率大幅度下降,因为对 Singleton2类来说,只有在第一次执行getInstance()方法时,才真正的需要对方法进行加锁同步,因为一旦第一次设置好instance 变量后,就不再需要同步这个方法了。之后每次调用这个方法,同步反而成了一种累赘。
3.用"双重检查加锁",在getInstance()方法中减少使用同步:
public class Singleton
{
// volatile关键字确保当instance变量被初始化成Singleton实例时,多个线程正确地处理instance变量
private volatile static Singleton instance;
private Singleton() {} public static Singleton getInstance()
{
if (instance == null) {// 检查实例,如是不存在就进行同步代码区
synchronized (Singleton.class) {// 对其进行加锁,防止两个线程同时进入同步代码区
if (instance == null) {// 双重检查,非常重要,如果两个同时访问的线程,当第一线程访问完同步代码区后,生成一个实例;当第二个已进入getInstance方法等待的线程进入同步代码区时,也会产生一个新的实例
instance = new Singleton();
}
}
}
return instance;
}
}
参考:
ITeye.com,java单例模式(Singleton pattern) : http://www.iteye.com/topic/652617
Java单例类的简单实现的更多相关文章
- java单例类/
java单例类 一个类只能创建一个实例,那么这个类就是一个单例类 可以重写toString方法 输出想要输出的内容 可以重写equcal来比较想要比较的内容是否相等 对于final修饰的成员变量 一 ...
- java单例类的几种实现
一,最简单的方式 public class Singleton{ private Singleton(){}; private static Singleton instance = new Sing ...
- Java 单例类
单例类:该类只能创建一个实例,或者说内存中只有一个实例,该类的对象引用的都是这个实例. 示例: package my_package; //定义一个单例类 class Singleton{ //使用一 ...
- 如何防止JAVA反射对单例类的攻击?
在我的上篇随笔中,我们知道了创建单例类有以下几种方式: (1).饿汉式; (2).懒汉式(.加同步锁的懒汉式.加双重校验锁的懒汉式.防止指令重排优化的懒汉式); (3).登记式单例模式; (4).静态 ...
- 设计模式(java) 单例模式 单例类
·单例类 单实例类,就是这个类只能创建一个对象,保证了对象实例的唯一性. 1.单例模式( Singleton Pattern) 是一个比较简单的模式, 其定义如下:Ensure a class has ...
- Java中Class和单例类的作用与类成员的理解
Java中Class类的作用与深入理解 在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识.这个信息跟踪着每个对象所属的类.JVM利用运行时信息选择相应的方法执行.而保存 ...
- 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类
static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...
- GCD实现简单的单例类-Singletion
什么是单例模式 1.单例模式是一个类在系统中只有一个实例对象.通过全局的一个入口点对这个实例对象进行访问.在 iOS 开发中,单例模式是非常有用的一种设计模式.如 下图,是一个简单单例模式的 UML ...
- [Android面试题-7] 写出一个Java的Singleton类(即单例类)
1.首先明确单例的概念和特点: a>单例类只能有一个实例 b>单例类必须自己创建一个自己的唯一实例 c>单例类必须为其他所有对象提供这个实例 2.单例具有几种模式,最简单的两种分别是 ...
随机推荐
- spring aop编程
1.AOP,面向切面编程(aspect Oriental programing),使用aop,可以将处理切面aspect的代码注入到主程序,通常主程序的主要目的不是处理这些切面aspect,可以防止代 ...
- linux常用的重要的命令: netstat
Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Membershi ...
- 绑定本地Service并与之通信-----之二
import android.os.Bundle;import android.os.IBinder;import android.app.Activity;import android.app.Se ...
- 网页优化URI(http URI scheme与data URI scheme)
网页优化的一大首要任务是减少HTTP 请求 (http request) 的次数,例如通过合并多个JS文件,合并CSS样式文件.除此之外,还有一个data URL 的密技,让我们直接把图像的内容崁入网 ...
- CodeIgniterCodeigniter+PHPExcel导出数据到Excel文件
解压压缩包里的Classes文件夹中的内容到application\libraries\目录下,目录结构如下:--application\libraries\PHPExcel.php--applica ...
- svm特征
svm特征格式:<label><index1>:<value1><index1>:<value1>.... 其中<label> ...
- [开发笔记]-火狐的event和jquery1.9.1.min的问题
一:火狐不兼容window.event.keyCode问题 火狐的event是以参数形式传入的 function onlychinese(event) { event = event || windo ...
- 学习linux与wp8.1——启航
现在不知不觉已经大三了,而本专业的东西没有多大感兴趣的,我看好wp开发和linux开发. 为什么要学习wp开发?其实就是一种兴趣,我手中有部620而已,学着学着就感兴趣了,所以打算继续学下去.同时,我 ...
- Hibernate中的一对一映射
1.需求 用户和身份证是一一对应的关系. 有两种对应方式: 用户id作为身份证表的外键,身份证号作为主键: 用户id作为身份证表的主键: 2.实体Bean设计 User: public class U ...
- Gartner报告:多数CIO还未对数字化做好准备
数字化经济时代已经来临.对于消费者而言,这意味着他们能够随时随地以更加丰富多彩的方式与虚拟世界和现实世界进行互动.对于企业而言,这意味着它们的运营将发生巨大变化,同时也有机会更加深入地了解客户并将这些 ...