Singleton Pattern
程序员文章站
2024-03-20 20:22:40
...
Singleton Pattern
有些时候我们只需要一个对象,比如:线程池、缓存、对话框、日志对象等。这类对象有且只能有一个实例,如果制造出多个实例,就会导致许多问题发生。例如:程序的行为异常、资源使用过量等。
利用单利模式可以像使用全局变量一样方便,可以全局访问,但全局变量需要在程序一开始就创建好对象,而使用单利模式可以让我们在需要时创建对象。
单件模式确保一个类只有一个实例,并提供一个全局访问点。
我们先来看看下面这段代码:
public class Singleton {
//利用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
//把构造器声明为私有的,类内才能访问
private Singleton() {}
//用getInstance()方法实例化对象,并返回这个实例
public static Singleton getInstance() {
if(uniqueInstance == null)//为空才创建实例
{
//如果我们不需要这个实例,则它永远不会被实例化。这就是“延迟实例化”。
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
但如果两个对象同时调用了getInstance()该怎么办呢?
我们可以采用线程同步的方法解决。
public class Singleton {
//利用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
//把构造器声明为私有的,类内才能访问
private Singleton() {}
/**
* 用getInstance()方法实例化对象,并返回这个实例
* 通过synchronized关键字我们可以使一个线程进入该方法前要先等待其他线程离开该方法
* 防止两个线程同时进入这个方法
*/
public static synchronized Singleton getInstance() {
if(uniqueInstance == null)//为空才创建实例
{
//如果我们不需要这个实例,则它永远不会被实例化。这就是“延迟实例化”。
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
但同步会降低性能,并且我们只是第一次执行该方法时需要同步。
我们应该怎样改善多线程呢?
如果应用程序总是创建并使用单件实例,或者是在运行和创建时的负担不是很重,我们可以使用“急切”创建实例。我们利用JVM在加载这个类时马上创建唯一的单件实例。
public class Singleton {
//在静态初始化器中创建单件。这段代码保证了线程安全
private static Singleton uniqueInstance=new Singleton;
//把构造器声明为私有的,类内才能访问
private Singleton() {}
// 用getInstance()方法实例化对象,并返回这个实例
public static Singleton getInstance() {
return uniqueInstance;
}
}
利用双重检查加锁,首先检查实例是否创建,未创建才进行同步。
public class Singleton {
//利用一个静态变量来记录Singleton类的唯一实例
//引入volatile防止编译器对代码进行优化
//确保当变量uniqueInstance被初始化成Singleton实例时,多个线程正确的处理变量uniqueInstance
private volatile static Singleton uniqueInstance;
//把构造器声明为私有的,类内才能访问
private Singleton() {}
/**
* 用getInstance()方法实例化对象,并返回这个实例
*/
public static Singleton getInstance() {
if(uniqueInstance == null)//为空才同步
{
synchronized(Singleton.class)
{
if(uniqueInstance == null)//为空才创建实例
{
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
在JAVA中单利模式常分为懒汉模式和饿汉模式。
懒汉模式:
package com.cauc.singleton;
/**
*
*
* LazySingleton
* 创建人:JasonZhang
* 时间:2018年6月30日-下午9:24:11
* @version 1.0.0
*
*/
public class LazySingleton {
/**
*
* 懒汉单利模式---运行时,编译时
* 格式:
* 1:构造函数私有化
* 2:公开的方法,返回当前实例的方法(static)的
*
*/
//声明类的唯一实例,使用private static修饰
private static LazySingleton singleton = null;
//将构造方式私有化,不允许外边直接创建对象
private LazySingleton(){
super();
}
//提供一个用于获取实例的方法,使用public static修饰
public synchronized static LazySingleton getInstance(){
if(singleton==null){
singleton = new LazySingleton();
}
return singleton;
}
}
饿汉模式:
package com.cauc.singleton;
/**
*
*
* EagerSingleton
* 创建人:JasonZhang
* 时间:2018年6月30日-下午9:25:34
* @version 1.0.0
*
*/
public class EagerSingleton {
//创建类的唯一实例,使用private static修饰
private static EagerSingleton singleton = new EagerSingleton();
//将构造方法私有化,不允许外部直接创建对象
private EagerSingleton(){
super();
}
//提供一个用于获取实例的方法,使用public static修饰
public static EagerSingleton getInstance(){
return singleton;
}
}
测试类:
package com.cauc.singleton;
/**
*
*
* Test
* 创建人:JasonZhang
* 时间:2018年6月30日-下午9:34:24
* @version 1.0.0
*
*/
public class Test {
public static void main(String[] args) {
//饿汉模式
EagerSingleton s1=EagerSingleton.getInstance();
EagerSingleton s2=EagerSingleton.getInstance();
if(s1==s2){
System.out.println("s1和s2是同一个实例");
}else{
System.out.println("s1和s2不是同一个实例");
}
//懒汉模式
LazySingleton s3=LazySingleton.getInstance();
LazySingleton s4=LazySingleton.getInstance();
if(s3==s4){
System.out.println("s3和s4是同一个实例");
}else{
System.out.println("S3和s4不是同一个实例");
}
}
}
上一篇: PHP读取大文件,并保存到数据库
下一篇: 开关灯问题(python)实现