[5]设计模式——单例模式

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点

 

安全的单例模式:

 

 

/*
 * @(#)Singleton.java  2014-8-1
 *
 * Copyright 2014 XXXX, Inc. All rights reserved.
 */
package com.fiberhome.singleton;

/**
 * 单例对象
 * 
 * @author liyan
 * @version 2014-8-1
 * @since 1.0
 */
public class Singleton
{
	/**
	 * 构造器似有化保证外部不能进行new操作
	 */
	private Singleton(){}
	
	/**
	 * 静态内部类保证线程安全
	 * 
	 * @author liyan
	 * @version 2014-8-1
	 * @since 1.0
	 */
	private static class SingleHolder
	{
		final static Singleton INSTANCE = new Singleton();
	}
	
	/**
	 * 获取实例对象的方法
	 * @return
	 */
	public static Singleton getInstance()
	{
		return SingleHolder.INSTANCE;
	}
	
	/**
	 * 普通的类方法
	 */
	public void doSth(){}
}

 不安全的单例设计:

 

/*
 * @(#)SingletonUnSafe.java  2014-8-1
 *
 * Copyright 2014 XXXX, Inc. All rights reserved.
 */
package com.fiberhome.singleton;

/**
 * 非线程安全的单例设计
 * 
 * @author liyan
 * @version 2014-8-1
 * @since 1.0
 */
public class SingletonUnSafe
{
	private static SingletonUnSafe sing;

	/**
	 * 似有化构造器
	 */
	private SingletonUnSafe()
	{
	}

	/**
	 * 获取实例方法
	 * @return
	 */
	public static SingletonUnSafe getInstance()
	{
		/*
		 * 首次初始化当前对象的一种假设情景
		 * 此时的代码块执行过程中的快照
		 * 两个实例化线程:Thrad1 and Thread2
		 */
		//线程切换Thrad2线程执行此处执行判断分支为True即将进入
		if (sing == null)
		{
			//Thrad1  刚进入代码块,还没有执行new指令
			sing = new SingletonUnSafe();
			
		}
		return sing;
	}

}

 

测试用例

/*
 * @(#)SingletonTest.java  2014-8-1
 *
 * Copyright 2014 XXXX, Inc. All rights reserved.
 */
package com.fiberhome.singleton;

import org.junit.Assert;
import org.junit.Test;

/**
 * 测试单例
 * 
 * @author liyan
 * @version 2014-8-1
 * @since 1.0
 * @see
 */
public class SingletonTest
{
	@Test
	public void singletonTestCase()
	{
		Assert.assertEquals(Singleton.getInstance(), Singleton.getInstance());
	}
}

 

 

    为什么静态内部类可以保证初始化单例对象的时候是线程安全的?

    静态内部类SingleHolder在获取其静态域的时候发送getstatic指令,虚拟机接收到这个指令立即对SingleHolder初始化,在调用SingleHolder构造器初始化之前首先完成其静态域的收集和初始化,静态域初始化完成以后是以单例的形式存在静态块区域的,随后调用构造器,构造器的初始化由jvm保证线程安全。所以静态内部类的这种初始化时线程安全的。

 

   关于类加载的时机

 

   类加载的“顺序”(非线性):加载->验证->准备->解析->初始化->使用-卸载

   在初始化阶段,虚拟机规范规定了只有4中情况必须立即对类进行初始化:    

  1. 遇到new ,getstatic,putstatic,invokestatic四条字节码指令。如果类没有进行初始化需要对其进行初    始化操作。    
  • new : 使用new关键字实例化对象的时候  
  • getstatic /putstatic : 读取或者设置一个类的静态字段  
  • invokestatic :调用一个类的静态方法
  1. 调用reflect包的方法对类进行反射调用的时候,如果没有初始化,需要对其进行初始化
  2. 初始化一个类的时候,返现其父类还没有初始化,则需要初始化其父类
  3. 当虚拟机启动的时候,用户需要指定一个要执行的主类,虚拟机会先初始化这个主类

 

 

------------------------------------------补充概念------------------------------------

类加载器

“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作的加载木块叫做“类加载器”

类加载器的分类:

  1. 启动类加载器(Bootstrap  ClassLoader):加载存在<JAVA_HOME>\lib 或者-Xbootclasspath目录中的,并且是虚拟机可识别的类库到虚拟机内存。Java程序无法直接引用启动类加载器
  2. 扩展类加载器:加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量指定的路径中的所有类库
  3. 应用程序类加载器:加载用户类路径(ClassPath)上指定的类库。

 

 

 

2014年8月1日 西安

[email protected]

 

 

你可能感兴趣的:(java,单例,设计模式,虚拟机)