求柯南柯南新剧场版唐红恋歌21唐红的恋歌百度云资源,谢谢

Java单例模式深入详解
我的图书馆
Java单例模式深入详解
一.问题引入
  偶然想想到的如果把Java的构造方法弄成private,那里面的成员属性是不是只有通过static来访问呢;如果构造方法是private的话,那么有什么好处呢;如果构造方法是private的话,会不更好的封装该内呢?我主要是应用在使用普通类模拟枚举类型里,后来发现这就是传说中的单例模式。构造函数弄成private 就是单例模式,即不想让别人用new 方法来创建多个对象,可以在类里面先生成一个对象,然后写一个public static方法把这个对象return出去。(eg:public 类名 getInstancd(){return 你刚刚生成的那个类对象;}),用static是因为你的构造函数是私有的,不能产生对象,所以只能用类名调用,所有只能是静态函数。成员变量也可以写getter/setter供外界访问的。如果谁要用这个类的实例就用有兴趣的读者参看我的这一篇博文/hxsyl/archive//2966360.html。
  第一个代码不是单例模式,也就是说不一定只要构造方法是private的就是单例模式。
1 class A(){
private A(){}
pulbic static A creatInstance(){
return new A();
<span style="COLOR: # }
<span style="COLOR: #
<span style="COLOR: # A a = A.createInstance();
<span style="COLOR: # a. //name 属性
1 public class single{
private static final single s=new single();
private single(){
public static single getInstance(){
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: # }
二.单例模式概念及特点
  java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。  单例模式有一下特点:  1、单例类只能有一个实例。  2、单例类必须自己自己创建自己的唯一实例。  3、单例类必须给所有其他对象提供这一实例。
  单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。
  正是由于这个特 点,单例对象通常作为程序中的存放配置信息的载体,因为它能保证其他对象读到一致的信息。例如在某个服务器程序中,该服务器的配置信息可能存放在数据库或 文件中,这些配置数据由某个单例对象统一读取,服务进程中的其他对象如果要获取这些配置信息,只需访问该单例对象即可。这种方式极大地简化了在复杂环境 下,尤其是多线程环境下的配置管理,但是随着应用场景的不同,也可能带来一些同步问题。
三.典型例题
  首先看一个经典的单例实现。
1 public class Singleton {
private static Singleton uniqueInstance = null;
private Singleton() {
// Exists only to defeat instantiation.
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
public static Singleton getInstance() {
<span style="COLOR: #
<span style="COLOR: #
if (uniqueInstance == null) {
<span style="COLOR: #
<span style="COLOR: #
uniqueInstance = new Singleton();
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
return uniqueI
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
// Other methods...
<span style="COLOR: #
<span style="COLOR: # }
  Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)
  但是以上实现没有考虑线程安全问题。所谓线程安全是指:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。显然以上实现并不满足线程安全的要求,在并发环境下很可能出现多个Singleton实例。
1 public class TestStream {
public String getName() {
public void setName(String name) {
this.name =
//该类只能有一个实例
<span style="COLOR: #
private TestStream(){}
//私有无参构造方法
<span style="COLOR: #
//该类必须自行创建
<span style="COLOR: #
//有2种方式
<span style="COLOR: #
/*private static final TestStream ts=new TestStream();*/
<span style="COLOR: #
private static TestStream ts1=null;
<span style="COLOR: #
//这个类必须自动向整个系统提供这个实例对象
<span style="COLOR: #
public static TestStream getTest(){
<span style="COLOR: #
if(ts1==null){
<span style="COLOR: #
ts1=new TestStream();
<span style="COLOR: #
<span style="COLOR: #
return ts1;
<span style="COLOR: #
<span style="COLOR: #
public void getInfo(){
<span style="COLOR: #
System.out.println("output message "+name);
<span style="COLOR: #
<span style="COLOR: #
1 public class TestMain {
public static void main(String [] args){
TestStream s=TestStream.getTest();
s.setName("张孝祥");
System.out.println(s.getName());
TestStream s1=TestStream.getTest();
s1.setName("张孝祥");
System.out.println(s1.getName());
s.getInfo();
<span style="COLOR: #
s1.getInfo();
<span style="COLOR: #
if(s==s1){
<span style="COLOR: #
System.out.println("创建的是同一个实例");
<span style="COLOR: #
}else if(s!=s1){
<span style="COLOR: #
System.out.println("创建的不是同一个实例");
<span style="COLOR: #
<span style="COLOR: #
System.out.println("application error");
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
运行结果:  张孝祥  张孝祥  output message 张孝祥  output message 张孝祥  创建的是同一个实例&结论:由结果可以得知单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都会同享一个实例对象。
  其次,下面是单例的三种实现。    
    1.饿汉式单例类
  飞哥下面这个可以不加final,因为静态方法只在编译期间执行一次初始化,也就是只会有一个对象。
1 //饿汉式单例类.在类初始化时,已经自行实例化
public class Singleton1 {
//私有的默认构造子
private Singleton1() {}
//已经自行实例化
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
<span style="COLOR: #
<span style="COLOR: #
    2.懒汉式单例类
  那个if判断确保对象只创建一次。
1 //懒汉式单例类.在第一次调用的时候实例化
public class Singleton2 {
//私有的默认构造子
private Singleton2() {}
//注意,这里没有final
private static Singleton2 single=null;
//静态工厂方法
public synchronized
static Singleton2 getInstance() {
if (single == null) {
<span style="COLOR: #
single = new Singleton2();
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
&    3.登记式单例类
1 import java.util.HashM
import java.util.M
//登记式单例类.
//类似Spring里面的方法,将类名注册,下次从里面直接获取。
public class Singleton3 {
private static Map&String,Singleton3& map = new HashMap&String,Singleton3&();
Singleton3 single = new Singleton3();
map.put(single.getClass().getName(), single);
<span style="COLOR: #
<span style="COLOR: #
//保护的默认构造子
<span style="COLOR: #
protected Singleton3(){}
<span style="COLOR: #
//静态工厂方法,返还此类惟一的实例
<span style="COLOR: #
public static Singleton3 getInstance(String name) {
<span style="COLOR: #
if(name == null) {
<span style="COLOR: #
name = Singleton3.class.getName();
<span style="COLOR: #
System.out.println("name == null"+"---&name="+name);
<span style="COLOR: #
<span style="COLOR: #
if(map.get(name) == null) {
<span style="COLOR: #
<span style="COLOR: #
map.put(name, (Singleton3) Class.forName(name).newInstance());
<span style="COLOR: #
} catch (InstantiationException e) {
<span style="COLOR: #
e.printStackTrace();
<span style="COLOR: #
} catch (IllegalAccessException e) {
<span style="COLOR: #
e.printStackTrace();
<span style="COLOR: #
} catch (ClassNotFoundException e) {
<span style="COLOR: #
e.printStackTrace();
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
return map.get(name);
<span style="COLOR: #
<span style="COLOR: #
//一个示意性的商业方法
<span style="COLOR: #
public String about() {
<span style="COLOR: #
return "Hello, I am RegSingleton.";
<span style="COLOR: #
<span style="COLOR: #
public static void main(String[] args) {
<span style="COLOR: #
Singleton3 single3 = Singleton3.getInstance(null);
<span style="COLOR: #
System.out.println(single3.about());
<span style="COLOR: #
<span style="COLOR: #
四.单例对象作配置信息管理时可能会带来的几个同步问题  
  1.在多线程环境下,单例对象的同步问题主要体现在两个方面,单例对象的初始化和单例对象的属性更新。
    本文描述的方法有如下假设:
    a. 单例对象的属性(或成员变量)的获取,是通过单例对象的初始化实现的。也就是说,在单例对象初始化时,会从文件或数据库中读取最新的配置信息。
    b. 其他对象不能直接改变单例对象的属性,单例对象属性的变化来源于配置文件或配置数据库数据的变化。
    1.1单例对象的初始化
      首先,讨论一下单例对象的初始化同步。单例模式的通常处理方式是,在对象中有一个静态成员变量,其类型就是单例类型本身;如果该变量为null,则创建该单例类型的对象,并将该变量指向这个对象;如果该变量不为null,则直接使用该变量。   
      这种处理方式在单线程的模式下可以很好的运行;但是在多线程模式下,可能产生问题。如果第一个线程发现成员变量为null,准备创建对象;这是第二 个线程同时也发现成员变量为null,也会创建新对象。这就会造成在一个JVM中有多个单例类型的实例。如果这个单例类型的成员变量在运行过程中变化,会 造成多个单例类型实例的不一致,产生一些很奇怪的现象。例如,某服务进程通过检查单例对象的某个属性来停止多个线程服务,如果存在多个单例对象的实例,就 会造成部分线程服务停止,部分线程服务不能停止的情况。
    1.2单例对象的属性更新
      通常,为了实现配置信息的实时更新,会有一个线程不停检测配置文件或配置数据库的内容,一旦发现变化,就更新到单例对象的属性中。在更新这些信 息的时候,很可能还会有其他线程正在读取这些信息,造成意想不到的后果。还是以通过单例对象属性停止线程服务为例,如果更新属性时读写不同步,可能访问该 属性时这个属性正好为空(null),程序就会抛出异常。
      下面是解决方法
1 //单例对象的初始化同步
2 public class GlobalConfig {
private static GlobalConfig instance = null;
private Vector properties = null;
private GlobalConfig() {
//Load configuration information from DB or file
//Set values for properties
private static synchronized void syncInit() {
<span style="COLOR: #
if (instance == null) {
<span style="COLOR: #
instance = new GlobalConfig();
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
public static GlobalConfig getInstance() {
<span style="COLOR: #
if (instance == null) {
<span style="COLOR: #
syncInit();
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
public Vector getProperties() {
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
  这种处理方式虽然引入了同步代码,但是因为这段同步代码只会在最开始的时候执行一次或多次,所以对整个系统的性能不会有影响。
  单例对象的属性更新同步。
  参照读者/写者的处理方式,设置一个读计数器,每次读取配置信息前,将计数器加1,读完后将计数器减1.只有在读计数器为0时,才能更新数据,同时要阻塞所有读属性的调用。
  代码如下:
1 public class GlobalConfig {
private static GlobalC
private Vector properties = null;
private boolean isUpdating = false;
private int readCount = 0;
private GlobalConfig() {
//Load configuration information from DB or file
//Set values for properties
<span style="COLOR: #
private static synchronized void syncInit() {
<span style="COLOR: #
if (instance == null) {
<span style="COLOR: #
instance = new GlobalConfig();
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
public static GlobalConfig getInstance() {
<span style="COLOR: #
if (instance==null) {
<span style="COLOR: #
syncInit();
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
public synchronized void update(String p_data) {
<span style="COLOR: #
syncUpdateIn();
<span style="COLOR: #
//Update properties
<span style="COLOR: #
<span style="COLOR: #
private synchronized void syncUpdateIn() {
<span style="COLOR: #
while (readCount & 0) {
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
} catch (Exception e) {
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
private synchronized void syncReadIn() {
<span style="COLOR: #
readCount++;
<span style="COLOR: #
<span style="COLOR: #
private synchronized void syncReadOut() {
<span style="COLOR: #
readCount--;
<span style="COLOR: #
notifyAll();
<span style="COLOR: #
<span style="COLOR: #
public Vector getProperties() {
<span style="COLOR: #
syncReadIn();
<span style="COLOR: #
//Process data
<span style="COLOR: #
syncReadOut();
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
  采用"影子实例"的办法具体说,就是在更新属性时,直接生成另一个单例对象实例,这个新生成的单例对象实例将从数据库或文件中读取最新的配置信息;然后将这些配置信息直接赋值给旧单例对象的属性。
1 public class GlobalConfig {
private static GlobalConfig instance = null;
private Vector properties = null;
private GlobalConfig() {
//Load configuration information from DB or file
//Set values for properties
private static synchronized void syncInit() {
if (instance = null) {
<span style="COLOR: #
instance = new GlobalConfig();
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
public static GlobalConfig getInstance() {
<span style="COLOR: #
if (instance = null) {
<span style="COLOR: #
syncInit();
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
public Vector getProperties() {
<span style="COLOR: #
<span style="COLOR: #
<span style="COLOR: #
public void updateProperties() {
<span style="COLOR: #
//Load updated configuration information by new a GlobalConfig object
<span style="COLOR: #
GlobalConfig shadow = new GlobalConfig();
<span style="COLOR: #
properties = shadow.getProperties();
<span style="COLOR: #
<span style="COLOR: #
注意:在更新方法中,通过生成新的GlobalConfig的实例,从文件或数据库中得到最新配置信息,并存放到properties属性中。上面两个方法比较起来,第二个方法更好,首先,编程更简单;其次,没有那么多的同步操作,对性能的影响也不大。
&五.结束语
  参考了很多资料才整理出了该内容,请大家多多指教,期间受益颇多,感觉到OS很重要,等把网络版的俄罗斯方块搞好后就去复习OS……加油,我是最棒的!!!
&  参考文献:/whgw/archive//2199535.html,http://blog.csdn.net/leesidong/article/details/6024455
TA的最新馆藏【转】JAVA 单例模式与多线程 - 学以致用 - ITeye技术网站
博客分类:
单例模式单例模式是一种常见的设计模式,分三种:懒汉式单例、饿汉式单例、内部类单例、登记式单例几种。
单例模式有一下特点:
1、单例类只能有一个实例。
2、单例类必须自己自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
懒汉模式不是线程安全的,饿汉模式是线程安全的,内部内模式利用Classloader的特,注册表模式是线程安全的同时又提供运行期指定单例。
饿汉式单例类:
public class Singleton
private Singleton(){
private static Singleton instance = new Singleton();
private static Singleton getInstance(){
内部类式单例类:
public class Singleton
private Singleton(){
private class SingletonHoledr(){
private static Singleton instance = new Singleton();
private static Singleton getInstance(){
return SingletonHoledr.
懒汉式单例类:
public class Singleton
private Singleton(){
private static S
public static synchronized Singleton getInstance(){
if(instance == null){
return instance = new Singleton();
这样写程序不会出错,因为整个getInstance是一个整体的"critical section",但就是效率很不好,因为我们的目的其实只是在第一个初始化instance的时候需要locking(加锁),而后面取用instance的时候,根本不需要线程同步。
于是聪明的人们想出了下面的做法:
双检锁写法:
public class Singleton{
private static S
//声明静态的单例对象的变量
private Singleton(){}
//私有构造方法
public static Singleton getSingle(){
//外部通过此方法可以获取对象
if(single == null){
synchronized (Singleton.class) {
//保证了同一时间只能只能有一个对象访问此同步块
if(single == null){
single = new Singleton();
//返回创建好的对象
public class Singleton{
private static S
//声明静态的单例对象的变量
private Singleton(){}
//私有构造方法
public static Singleton getSingle(){
//外部通过此方法可以获取对象
if(single == null){
synchronized (Singleton.class) {
//保证了同一时间只能只能有一个对象访问此同步块
if(single == null){
single = new Singleton();
//返回创建好的对象
思路很简单,就是我们只需要同步(synchronize)初始化instance的那部分代码从而使代码既正确又很有效率。
这就是所谓的“双检锁”机制(顾名思义)。
很可惜,这样的写法在很多平台和优化编译器上是错误的。
原因在于:instance = new Singleton()这行代码在不同编译器上的行为是无法预知的。一个优化编译器可以合法地如下实现instance = new Singleton():
1. instance = 给新的实体分配内存
2. 调用Singleton的构造函数来初始化instance的成员变量
现在想象一下有线程A和B在调用getInstance,线程A先进入,在执行到步骤1的时候被踢出了cpu。然后线程B进入,B看到的是instance 已经不是null了(内存已经分配),于是它开始放心地使用instance,但这个是错误的,因为在这一时刻,instance的成员变量还都是缺省值,A还没有来得及执行步骤2来完成instance的初始化。
当然编译器也可以这样实现:
1. temp = 分配内存
2. 调用temp的构造函数
3. instance = temp
如果编译器的行为是这样的话我们似乎就没有问题了,但事实却不是那么简单,因为我们无法知道某个编译器具体是怎么做的,因为在Java的memory model里对这个问题没有定义。
双检锁对于基础类型(比如int)适用。很显然吧,因为基础类型没有调用构造函数这一步。
浏览: 113676 次
来自: 杭州
你好,请问我用Captcha captcha = config ...
大神arraylist完了,linkedList呢,set,m ...
ensureCapacityInternal不是“确保内部容量 ...
* The maximum size of a ...
transient修饰符让elementData无法自动序列化 ...java单例模式的一个小结 - MMY - ITeye技术网站
博客分类:
单例模式单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。单例模式有一下特点:1、单例类只能有一个实例。2、单例类必须自己自己创建自己的唯一实例。3、单例类必须给所有其他对象提供这一实例。
一、懒汉式单例在类被加载的时候,唯一实例已经被创建。这个设计模式在Java中容易实现,在别的语言中难以实现。单例模式-懒汉式单例public class LazySingleton {
/*** 私有静态对象,加载时候不做初始化
private static LazySingleton m_intance=
/*** 私有构造方法,避免外部创建实例
private LazySingleton(){}
/*** 静态工厂方法,返回此类的唯一实例.* 当发现实例没有初始化的时候,才初始化. * @return LazySingleton */
synchronized public static LazySingleton getInstance(){
if(m_intance==null){
m_intance=new LazySingleton();
}}//测试一下单例模式
LazySingleton lazySingleton = LazySingleton.getInstance();
LazySingleton lazySingleton1 = LazySingleton.getInstance();
if(lazySingleton==lazySingleton1)){
System.out.println("同一个对象实例");
System.out.println("不是同一个对象实例");
二、饿汉式单例在类加载的时候不创建单例实例。只有在第一次请求实例的时候的时候创建,并且只在第一次创建后,以后不再创建该类的实例。/***单例模式-饿汉式单例*/public class EagerSingleton {
/**私有的(private)唯一(static final)实例成员,在类加载的时候就创建好了单例对象*/
private static final EagerSingleton m_instance = new EagerSingleton();
/*** 私有构造方法,避免外部创建实例
private EagerSingleton() {}
//提供了一个空的构造方法
/*** 静态工厂方法,返回此类的唯一实例.* @return EagerSingleton
public static EagerSingleton getInstance() {
//下面来判断一下有没有达到单例效果(系统运行的时候只出来一个空例)
EagerSingleton eagerSingleton = EagerSingleton.getInstance();
EagerSingleton eagerSingleton1 = EagerSingleton.getInstance();
if(eagerSingleton==eagerSingleton1)){
System.out.println("同一个对象实例");
System.out.println("不是同一个对象实例");
三、登记式单例这个单例实际上维护的是一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从工厂直接返回,对于没有登记的,则先登记,而后返回。/*** 单例模式- 登记式单例*/public class RegSingleton {
/*** 登记薄,用来存放所有登记的实例
private static Map&String, RegSingleton& m_registry = new HashMap();
//在类加载的时候添加一个实例到登记薄
RegSingleton x = new RegSingleton();
m_registry.put(x.getClass().getName(), x);
/*** 受保护的默认构造方法*/
protected RegSingleton() {}
/*** 静态工厂方法,返回指定登记对象的唯一实例;
* 对于已登记的直接取出返回,对于还未登记的,先登记,然后取出返回
* @param name
RegSingleton
public static RegSingleton getInstance(String name) {
if (name == null) {
name = "RegSingleton";
if (m_registry.get(name) == null) {
m_registry.put(name, (RegSingleton) Class.forName(name).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
return m_registry.get(name);
/** * 一个示意性的商业方法
* @return String
public String about() {
return "Hello,I am RegSingleton!";
四、单例模式的一个应用该应用是配置文件管理类。为了本例能正确运行,我在C盘下先建立了一个xxxx.properties文件,内容如下:-------------------
user=rootpassword=leizhimin这个配置文件管理类的代码如下:单例模式应用-单例类应用-配置文件管理*/public class ConfigManager {
/*** 属性文件全名*/
private static final String PFILE = "C:\\xxx.properties";
你正好相反过来,懒汉和饿汉博主也没完全弄反吧?基本上是那样,就懒汉式的第一段话说成饿汉式的啦吧。
mamaoyuan625
浏览: 133714 次
来自: 成都
好的,谢谢你的支持
好的 谢谢了
lucane 写道你好--4.总分前三的所有学生名单(包括并列 ...
学习了 谢谢分享

我要回帖

更多关于 柯南剧场版唐红的恋歌 的文章

 

随机推荐