1、单例模式定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点 。
2、单例模式结构及说明:Singleton:负责创建Singleton类自己的唯一实例,并提供一个getInstance的方法,让外部来访问这个类的唯一实例。
3、单例模式示例代码:
3.1 单例模式又分为饿汉式与懒汉式单例模式。
饿与懒的区别,饿表示的是在程序加载的时候即创建一个静态实例。懒顾名思义即当在需要他的时候才会创建。
3.2 恶汉式代码:
package singleton;
/**
* 懒汉式单例模式
* @author Administrator
*
*/
public class SingletonSample2 {
/**
* 定义一个变量来存储创建好的类的实例
*/
private static SingletonSample2 uniqueInstance= null;
/**
* 私有构造方法,可以在内部控制创建实例的数目
*/
private SingletonSample2(){
}
/**
* 定义一个方法来为客户端提供实例
* @return
*/
public static synchronized SingletonSample2 getInstance(){
//判断存储实例的变量是否有值
if(null == uniqueInstance){
//如果没有,就创建一个类实例,并把值赋给存储类实例的变量
uniqueInstance = new SingletonSample2();
}
//有值就直接返回
return uniqueInstance;
}
/**
* 定义自己的方法
*/
public void singletonOperation(){
}
/**
* 定义自己的属性
*/
private String singletonData;
public String getSingletonData() {
return singletonData;
}
public void setSingletonData(String singletonData) {
this.singletonData = singletonData;
}
}
测试类
public class SingletonTest {
public static void main(String[] args) {
SingletonSample2 s21 = SingletonSample2.getInstance();
SingletonSample2 s22 = SingletonSample2.getInstance();
System.out.println(s21==s22);
}
}
测试结果:返回true
3.2 懒汉式代码:
package singleton;
/**
* 恶汉式单例模式
* @author Administrator
*
*/
public class SingletonSample1 {
/**
* 定义一个变量来存储创建好的类的实例,直接在这里创建类的实例,只能创建一次
*/
private static SingletonSample1 uniqueInstance= new SingletonSample1();
/**
* 私有构造方法,可以在内部控制创建实例的数目
*/
private SingletonSample1(){
}
/**
* 定义一个方法来为客户端提供实例
* @return
*/
public static SingletonSample1 getInstance(){
return uniqueInstance;
}
/**
* 定义自己的方法
*/
public void singletonOperation(){
}
/**
* 定义自己的属性
*/
private String singletonData;
public String getSingletonData() {
return singletonData;
}
public void setSingletonData(String singletonData) {
this.singletonData = singletonData;
}
}
4、单例模式线程安全性: 不加同步的懒汉式是线程不安全的,在多线程的环境中可能会导致并发问题。而饿汉式是线程安全的,因为虚拟机保证只会装载一次,在装载类的时候不会发生并发的。
4.1 如何实现懒汉式线程安全呢? 当然可以直接在getInstance()方法上加上synchronized关键字。但这样就会降低整个访问的速度,而且每次都要判断。故出现了双重检查加锁。
4.2 双重检查加锁机制:指的是并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块过后,再次检查实例是否存在如果不存在,就在同步块的情况下创建一个实例,这就是第二重检查。这样一来,就只需要同步一次了。从而减少了多次在同步的情况下进行的判断而浪费的时间。 不多说,上代码。
package singleton;
/**
* 双重检查加锁懒汉式单例模式
* @author Administrator
*
*/
public class SingletonSample3 {
/**
* 定义一个变量来存储创建好的类的实例需添加volatile修饰
*/
private volatile static SingletonSample3 uniqueInstance= null;
/**
* 私有构造方法,可以在内部控制创建实例的数目
*/
private SingletonSample3(){
}
/**
* 定义一个方法来为客户端提供实例
* @return
*/
public static SingletonSample3 getInstance(){
//判断存储实例的变量是否有值
if(null == uniqueInstance){
//同步块,线程安全地创建实例
synchronized (SingletonSample3.class) {
//再次检查实例是否存在,如果不存在才真正的创建实例
if(null == uniqueInstance){
uniqueInstance = new SingletonSample3();
}
}
}
//有值就直接返回
return uniqueInstance;
}
/**
* 定义自己的方法
*/
public void singletonOperation(){
}
/**
* 定义自己的属性
*/
private String singletonData;
public String getSingletonData() {
return singletonData;
}
public void setSingletonData(String singletonData) {
this.singletonData = singletonData;
}
}
(建议双重检查加锁用在java5及以上版本。)
5、单例模式的更好实现方式:类级内部类。
5.1 类级内部类:有static修饰的成员式内部类。如果没有static修饰的成员内部类被称为对象内部类。
5.2 多线程缺省同步锁。
在多线程开发中,为了解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制。但是某些情况中,虚拟机已经隐含地为您执行了同步,这些情况就不用直接再来进行同步控制了。这些情况包括:
- 由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时
- 访问final字段时
- 在创建线程之间创建对象
- 线程可以看见它要处理的对象时
5.3 更为简单的实现单例模式实例代码
package singleton;
/**
* 双重检查加锁懒汉式单例模式
* @author Administrator
*
*/
public class SingletonSample4 {
/**
* 类级内部类
* 没有绑定关系,而且只有在调用的时候才会加载,从而实现了延迟加载
*/
private static class SingletonHolder{
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static SingletonSample4 instance = new SingletonSample4();
}
public static SingletonSample4 getInstance(){
return SingletonHolder.instance;
}
/**
* 私有构造方法
*/
private SingletonSample4(){
}
/**
* 定义自己的方法
*/
public void singletonOperation(){
}
/**
* 定义自己的属性
*/
private String singletonData;
public String getSingletonData() {
return singletonData;
}
public void setSingletonData(String singletonData) {
this.singletonData = singletonData;
}
}
6、还有种更为简洁,高效,安全的实现单例方法---
通过枚举来显示单例模式。
package singleton;
public enum SingletonSample5 {
/**
* 定义一个枚举元素,它就代表了Singleton的一个实例
*/
uniqueInstance;
/**
* 自定义方法
*/
public void singletonOperation(){
}
}
以上是单例的模式的几种不同的实现方式,与大家一同学习。
Little progress every day!