高并发下线程安全的单例模式

复制来自 http://blog.csdn.net/cselmu9/article/details/51366946java

在全部的设计模式中,单例模式是咱们在项目开发中最为常见的设计模式之一,而单例模式有不少种实现方式,你是否都了解呢?高并发下如何保证单例模式的线程安全性呢?如何保证序列化后的单例对象在反序列化后任然是单例的呢?这些问题在看了本文以后都会一一的告诉你答案,赶快来阅读吧!mysql

什么是单例模式?

在文章开始以前咱们仍是有必要介绍一下什么是单例模式。单例模式是为确保一个类只有一个实例,并为整个系统提供一个全局访问点的一种模式方法。sql

从概念中体现出了单例的一些特色:数据库

(1)、在任何状况下,单例类永远只有一个实例存在编程

(2)、单例须要有能力为整个系统提供这一惟一实例  设计模式

 

为了便于读者更好的理解这些概念,下面给出这么一段内容叙述:缓存

在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具备资源管理器的功能。每台计算机能够有若干个打印机,但只能有一个Printer Spooler,以免两个打印做业同时输出到打印机中。每台计算机能够有若干通讯端口,系统应当集中管理这些通讯端口,以免一个通讯端口同时被两个请求同时调用。总之,选择单例模式就是为了不不一致状态,避免政出多头。

正是因为这个特色,单例对象一般做为程序中的存放配置信息的载体,由于它能保证其余对象读到一致的信息。例如在某个服务器程序中,该服务器的配置信息可能存放在数据库或文件中,这些配置数据由某个单例对象统一读取,服务进程中的其余对象若是要获取这些配置信息,只需访问该单例对象便可。这种方式极大地简化了在复杂环境 下,尤为是多线程环境下的配置管理,可是随着应用场景的不一样,也可能带来一些同步问题。
    安全

各式各样的单例实现

舒适提示:本文叙述中涉及到的相关源码能够在这里进行下载源码,读者可免积分下载。服务器

一、饿汉式单例

饿汉式单例是指在方法调用前,实例就已经建立好了。下面是实现代码:多线程

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s01;  
  2.   
  3. public class MySingleton {  
  4.       
  5.     private static MySingleton instance = new MySingleton();  
  6.       
  7.     private MySingleton(){}  
  8.       
  9.     public static MySingleton getInstance() {  
  10.         return instance;  
  11.     }  
  12.       
  13. }  

以上是单例的饿汉式实现,咱们来看看饿汉式在多线程下的执行状况,给出一段多线程的执行代码:

 

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s01;  
  2.   
  3. public class MyThread extends Thread{  
  4.       
  5.     @Override  
  6.     public void run() {   
  7.         System.out.println(MySingleton.getInstance().hashCode());  
  8.     }  
  9.       
  10.     public static void main(String[] args) {   
  11.           
  12.         MyThread[] mts = new MyThread[10];  
  13.         for(int i = 0 ; i < mts.length ; i++){  
  14.             mts[i] = new MyThread();  
  15.         }  
  16.           
  17.         for (int j = 0; j < mts.length; j++) {  
  18.             mts[j].start();  
  19.         }  
  20.     }  
  21. }  

以上代码运行结果:

 

[plain]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 1718900954  
  2. 1718900954  
  3. 1718900954  
  4. 1718900954  
  5. 1718900954  
  6. 1718900954  
  7. 1718900954  
  8. 1718900954  
  9. 1718900954  
  10. 1718900954  


从运行结果能够看出实例变量额hashCode值一致,这说明对象是同一个,饿汉式单例实现了。

 

 

二、懒汉式单例

懒汉式单例是指在方法调用获取实例时才建立实例,由于相对饿汉式显得“不急迫”,因此被叫作“懒汉模式”。下面是实现代码:

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s02;  
  2.   
  3. public class MySingleton {  
  4.       
  5.     private static MySingleton instance = null;  
  6.       
  7.     private MySingleton(){}  
  8.       
  9.     public static MySingleton getInstance() {  
  10.         if(instance == null){//懒汉式  
  11.             instance = new MySingleton();  
  12.         }  
  13.         return instance;  
  14.     }  
  15. }  

这里实现了懒汉式的单例,可是熟悉多线程并发编程的朋友应该能够看出,在多线程并发下这样的实现是没法保证明例实例惟一的,甚至能够说这样的失效是彻底错误的,下面咱们就来看一下多线程并发下的执行状况,这里为了看到效果,咱们对上面的代码作一小点修改:

 

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s02;  
  2.   
  3. public class MySingleton {  
  4.       
  5.     private static MySingleton instance = null;  
  6.       
  7.     private MySingleton(){}  
  8.       
  9.     public static MySingleton getInstance() {  
  10.         try {   
  11.             if(instance != null){//懒汉式   
  12.                   
  13.             }else{  
  14.                 //建立实例以前可能会有一些准备性的耗时工做   
  15.                 Thread.sleep(300);  
  16.                 instance = new MySingleton();  
  17.             }  
  18.         } catch (InterruptedException e) {   
  19.             e.printStackTrace();  
  20.         }  
  21.         return instance;  
  22.     }  
  23. }  

这里假设在建立实例前有一些准备性的耗时工做要处理,多线程调用:

 

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s02;  
  2.   
  3. public class MyThread extends Thread{  
  4.       
  5.     @Override  
  6.     public void run() {   
  7.         System.out.println(MySingleton.getInstance().hashCode());  
  8.     }  
  9.       
  10.     public static void main(String[] args) {   
  11.           
  12.         MyThread[] mts = new MyThread[10];  
  13.         for(int i = 0 ; i < mts.length ; i++){  
  14.             mts[i] = new MyThread();  
  15.         }  
  16.           
  17.         for (int j = 0; j < mts.length; j++) {  
  18.             mts[j].start();  
  19.         }  
  20.     }  
  21. }  

执行结果以下:

 

[plain]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 1210420568  
  2. 1210420568  
  3. 1935123450  
  4. 1718900954  
  5. 1481297610  
  6. 1863264879  
  7. 369539795  
  8. 1210420568  
  9. 1210420568  
  10. 602269801  


从这里执行结果能够看出,单例的线程安全性并无获得保证,那要怎么解决呢?

 

 

三、线程安全的懒汉式单例

要保证线程安全,咱们就得须要使用同步锁机制,下面就来看看咱们如何一步步的解决 存在线程安全问题的懒汉式单例(错误的单例)。

(1)、 方法中声明synchronized关键字

出现非线程安全问题,是因为多个线程能够同时进入getInstance()方法,那么只须要对该方法进行synchronized的锁同步便可:

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s03;  
  2.   
  3. public class MySingleton {  
  4.       
  5.     private static MySingleton instance = null;  
  6.       
  7.     private MySingleton(){}  
  8.       
  9.     public synchronized static MySingleton getInstance() {  
  10.         try {   
  11.             if(instance != null){//懒汉式   
  12.                   
  13.             }else{  
  14.                 //建立实例以前可能会有一些准备性的耗时工做   
  15.                 Thread.sleep(300);  
  16.                 instance = new MySingleton();  
  17.             }  
  18.         } catch (InterruptedException e) {   
  19.             e.printStackTrace();  
  20.         }  
  21.         return instance;  
  22.     }  
  23. }  

此时任然使用前面验证多线程下执行状况的MyThread类来进行验证,将其放入到org.mlinge.s03包下运行,执行结果以下:

 

[plain]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 1689058373  
  2. 1689058373  
  3. 1689058373  
  4. 1689058373  
  5. 1689058373  
  6. 1689058373  
  7. 1689058373  
  8. 1689058373  
  9. 1689058373  
  10. 1689058373  

 

从执行结果上来看,问题已经解决了,可是这种实现方式的运行效率会很低。同步方法效率低,那咱们考虑使用同步代码块来实现:

 

(2)、 同步代码块实现

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s03;  
  2.   
  3. public class MySingleton {  
  4.       
  5.     private static MySingleton instance = null;  
  6.       
  7.     private MySingleton(){}  
  8.       
  9.     //public synchronized static MySingleton getInstance() {  
  10.     public static MySingleton getInstance() {  
  11.         try {   
  12.             synchronized (MySingleton.class) {  
  13.                 if(instance != null){//懒汉式   
  14.                       
  15.                 }else{  
  16.                     //建立实例以前可能会有一些准备性的耗时工做   
  17.                     Thread.sleep(300);  
  18.                     instance = new MySingleton();  
  19.                 }  
  20.             }  
  21.         } catch (InterruptedException e) {   
  22.             e.printStackTrace();  
  23.         }  
  24.         return instance;  
  25.     }  
  26. }  

这里的实现可以保证多线程并发下的线程安全性,可是这样的实现将所有的代码都被锁上了,一样的效率很低下。

 

(3)、 针对某些重要的代码来进行单独的同步(可能非线程安全)

针对某些重要的代码进行单独的同步,而不是所有进行同步,能够极大的提升执行效率,咱们来看一下:

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s04;  
  2.   
  3. public class MySingleton {  
  4.       
  5.     private static MySingleton instance = null;  
  6.       
  7.     private MySingleton(){}  
  8.        
  9.     public static MySingleton getInstance() {  
  10.         try {    
  11.             if(instance != null){//懒汉式   
  12.                   
  13.             }else{  
  14.                 //建立实例以前可能会有一些准备性的耗时工做   
  15.                 Thread.sleep(300);  
  16.                 synchronized (MySingleton.class) {  
  17.                     instance = new MySingleton();  
  18.                 }  
  19.             }   
  20.         } catch (InterruptedException e) {   
  21.             e.printStackTrace();  
  22.         }  
  23.         return instance;  
  24.     }  
  25. }  

此时一样使用前面验证多线程下执行状况的MyThread类来进行验证,将其放入到org.mlinge.s04包下运行,执行结果以下:

[plain]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 1481297610  
  2. 397630378  
  3. 1863264879  
  4. 1210420568  
  5. 1935123450  
  6. 369539795  
  7. 590202901  
  8. 1718900954  
  9. 1689058373  
  10. 602269801  

从运行结果来看,这样的方法进行代码块同步,代码的运行效率是可以获得提高,可是却没能保住线程的安全性。看来还得进一步考虑如何解决此问题。

 

(4)、 Double Check Locking 双检查锁机制(推荐)

为了达到线程安全,又能提升代码执行效率,咱们这里能够采用DCL的双检查锁机制来完成,代码实现以下:

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s05;  
  2.   
  3. public class MySingleton {  
  4.       
  5.     //使用volatile关键字保其可见性  
  6.     volatile private static MySingleton instance = null;  
  7.       
  8.     private MySingleton(){}  
  9.        
  10.     public static MySingleton getInstance() {  
  11.         try {    
  12.             if(instance != null){//懒汉式   
  13.                   
  14.             }else{  
  15.                 //建立实例以前可能会有一些准备性的耗时工做   
  16.                 Thread.sleep(300);  
  17.                 synchronized (MySingleton.class) {  
  18.                     if(instance == null){//二次检查  
  19.                         instance = new MySingleton();  
  20.                     }  
  21.                 }  
  22.             }   
  23.         } catch (InterruptedException e) {   
  24.             e.printStackTrace();  
  25.         }  
  26.         return instance;  
  27.     }  
  28. }  

将前面验证多线程下执行状况的MyThread类放入到org.mlinge.s05包下运行,执行结果以下:

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 369539795  
  2. 369539795  
  3. 369539795  
  4. 369539795  
  5. 369539795  
  6. 369539795  
  7. 369539795  
  8. 369539795  
  9. 369539795  
  10. 369539795  

从运行结果来看,该中方法保证了多线程并发下的线程安全性。

 

这里在声明变量时使用了volatile关键字来保证其线程间的可见性;在同步代码块中使用二次检查,以保证其不被重复实例化。集合其两者,这种实现方式既保证了其高效性,也保证了其线程安全性。

四、使用静态内置类实现单例模式

DCL解决了多线程并发下的线程安全问题,其实使用其余方式也能够达到一样的效果,代码实现以下:

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s06;  
  2.   
  3. public class MySingleton {  
  4.       
  5.     //内部类  
  6.     private static class MySingletonHandler{  
  7.         private static MySingleton instance = new MySingleton();  
  8.     }   
  9.       
  10.     private MySingleton(){}  
  11.        
  12.     public static MySingleton getInstance() {   
  13.         return MySingletonHandler.instance;  
  14.     }  
  15. }  

以上代码就是使用静态内置类实现了单例模式,这里将前面验证多线程下执行状况的MyThread类放入到org.mlinge.s06包下运行,执行结果以下:

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 1718900954  
  2. 1718900954  
  3. 1718900954  
  4. 1718900954  
  5. 1718900954  
  6. 1718900954  
  7. 1718900954  
  8. 1718900954  
  9. 1718900954  
  10. 1718900954  

从运行结果来看,静态内部类实现的单例在多线程并发下单个实例获得了保证。

 

五、序列化与反序列化的单例模式实现

静态内部类虽然保证了单例在多线程并发下的线程安全性,可是在遇到序列化对象时,默认的方式运行获得的结果就是多例的。

代码实现以下:

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s07;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class MySingleton implements Serializable {  
  6.        
  7.     private static final long serialVersionUID = 1L;  
  8.   
  9.     //内部类  
  10.     private static class MySingletonHandler{  
  11.         private static MySingleton instance = new MySingleton();  
  12.     }   
  13.       
  14.     private MySingleton(){}  
  15.        
  16.     public static MySingleton getInstance() {   
  17.         return MySingletonHandler.instance;  
  18.     }  
  19. }  

序列化与反序列化测试代码:

 

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s07;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileNotFoundException;  
  6. import java.io.FileOutputStream;  
  7. import java.io.IOException;  
  8. import java.io.ObjectInputStream;  
  9. import java.io.ObjectOutputStream;  
  10.   
  11. public class SaveAndReadForSingleton {  
  12.       
  13.     public static void main(String[] args) {  
  14.         MySingleton singleton = MySingleton.getInstance();  
  15.           
  16.         File file = new File("MySingleton.txt");  
  17.           
  18.         try {  
  19.             FileOutputStream fos = new FileOutputStream(file);  
  20.             ObjectOutputStream oos = new ObjectOutputStream(fos);  
  21.             oos.writeObject(singleton);  
  22.             fos.close();  
  23.             oos.close();  
  24.             System.out.println(singleton.hashCode());  
  25.         } catch (FileNotFoundException e) {   
  26.             e.printStackTrace();  
  27.         } catch (IOException e) {   
  28.             e.printStackTrace();  
  29.         }  
  30.           
  31.         try {  
  32.             FileInputStream fis = new FileInputStream(file);  
  33.             ObjectInputStream ois = new ObjectInputStream(fis);  
  34.             MySingleton rSingleton = (MySingleton) ois.readObject();  
  35.             fis.close();  
  36.             ois.close();  
  37.             System.out.println(rSingleton.hashCode());  
  38.         } catch (FileNotFoundException e) {   
  39.             e.printStackTrace();  
  40.         } catch (IOException e) {   
  41.             e.printStackTrace();  
  42.         } catch (ClassNotFoundException e) {   
  43.             e.printStackTrace();  
  44.         }  
  45.           
  46.     }  
  47. }  

运行以上代码,获得的结果以下:

 

 

[sql]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 865113938  
  2. 1442407170  

从结果中咱们发现,序列号对象的hashCode和反序列化后获得的对象的hashCode值不同,说明反序列化后返回的对象是从新实例化的,单例被破坏了。那怎么来解决这一问题呢?

 

解决办法就是在反序列化的过程当中使用readResolve()方法,单例实现的代码以下:

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s07;  
  2.   
  3. import java.io.ObjectStreamException;  
  4. import java.io.Serializable;  
  5.   
  6. public class MySingleton implements Serializable {  
  7.        
  8.     private static final long serialVersionUID = 1L;  
  9.   
  10.     //内部类  
  11.     private static class MySingletonHandler{  
  12.         private static MySingleton instance = new MySingleton();  
  13.     }   
  14.       
  15.     private MySingleton(){}  
  16.        
  17.     public static MySingleton getInstance() {   
  18.         return MySingletonHandler.instance;  
  19.     }  
  20.       
  21.     //该方法在反序列化时会被调用,该方法不是接口定义的方法,有点儿约定俗成的感受  
  22.     protected Object readResolve() throws ObjectStreamException {  
  23.         System.out.println("调用了readResolve方法!");  
  24.         return MySingletonHandler.instance;   
  25.     }  
  26. }  

再次运行上面的测试代码,获得的结果以下:

 

 

[plain]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 865113938  
  2. 调用了readResolve方法!  
  3. 865113938  

从运行结果可知,添加readResolve方法后反序列化后获得的实例和序列化前的是同一个实例,单个实例获得了保证。

 

六、使用static代码块实现单例

静态代码块中的代码在使用类的时候就已经执行了,因此能够应用静态代码块的这个特性的实现单例设计模式。

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s08;  
  2.   
  3. public class MySingleton{  
  4.        
  5.     private static MySingleton instance = null;  
  6.        
  7.     private MySingleton(){}  
  8.   
  9.     static{  
  10.         instance = new MySingleton();  
  11.     }  
  12.       
  13.     public static MySingleton getInstance() {   
  14.         return instance;  
  15.     }   
  16. }  

测试代码以下:

 

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s08;  
  2.   
  3. public class MyThread extends Thread{  
  4.       
  5.     @Override  
  6.     public void run() {   
  7.         for (int i = 0; i < 5; i++) {  
  8.             System.out.println(MySingleton.getInstance().hashCode());  
  9.         }  
  10.     }  
  11.       
  12.     public static void main(String[] args) {   
  13.           
  14.         MyThread[] mts = new MyThread[3];  
  15.         for(int i = 0 ; i < mts.length ; i++){  
  16.             mts[i] = new MyThread();  
  17.         }  
  18.           
  19.         for (int j = 0; j < mts.length; j++) {  
  20.             mts[j].start();  
  21.         }  
  22.     }  
  23. }  

运行结果以下:

 

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 1718900954  
  2. 1718900954  
  3. 1718900954  
  4. 1718900954  
  5. 1718900954  
  6. 1718900954  
  7. 1718900954  
  8. 1718900954  
  9. 1718900954  
  10. 1718900954  
  11. 1718900954  
  12. 1718900954  
  13. 1718900954  
  14. 1718900954  
  15. 1718900954  

从运行结果看,单例的线程安全性获得了保证。

 

七、使用枚举数据类型实现单例模式

枚举enum和静态代码块的特性类似,在使用枚举时,构造方法会被自动调用,利用这一特性也能够实现单例:

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s09;  
  2.   
  3. public enum EnumFactory{   
  4.       
  5.     singletonFactory;  
  6.       
  7.     private MySingleton instance;  
  8.       
  9.     private EnumFactory(){//枚举类的构造方法在类加载是被实例化  
  10.         instance = new MySingleton();  
  11.     }  
  12.           
  13.     public MySingleton getInstance(){  
  14.         return instance;  
  15.     }  
  16.       
  17. }  
  18.   
  19. class MySingleton{//须要获实现单例的类,好比数据库链接Connection  
  20.     public MySingleton(){}   
  21. }  

测试代码以下:

 

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s09;  
  2.   
  3. public class MyThread extends Thread{  
  4.       
  5.     @Override  
  6.     public void run() {   
  7.         System.out.println(EnumFactory.singletonFactory.getInstance().hashCode());  
  8.     }  
  9.       
  10.     public static void main(String[] args) {   
  11.           
  12.         MyThread[] mts = new MyThread[10];  
  13.         for(int i = 0 ; i < mts.length ; i++){  
  14.             mts[i] = new MyThread();  
  15.         }  
  16.           
  17.         for (int j = 0; j < mts.length; j++) {  
  18.             mts[j].start();  
  19.         }  
  20.     }  
  21. }  

执行后获得的结果:

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 1481297610  
  2. 1481297610  
  3. 1481297610  
  4. 1481297610  
  5. 1481297610  
  6. 1481297610  
  7. 1481297610  
  8. 1481297610  
  9. 1481297610  
  10. 1481297610  

运行结果代表单例获得了保证,可是这样写枚举类被彻底暴露了,听说违反了“职责单一原则”,那咱们来看看怎么进行改造呢。

 

八、完善使用enum枚举实现单例模式

不暴露枚举类实现细节的封装代码以下:

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s10;  
  2.   
  3. public class ClassFactory{   
  4.       
  5.     private enum MyEnumSingleton{  
  6.         singletonFactory;  
  7.           
  8.         private MySingleton instance;  
  9.           
  10.         private MyEnumSingleton(){//枚举类的构造方法在类加载是被实例化  
  11.             instance = new MySingleton();  
  12.         }  
  13.    
  14.         public MySingleton getInstance(){  
  15.             return instance;  
  16.         }  
  17.     }   
  18.    
  19.     public static MySingleton getInstance(){  
  20.         return MyEnumSingleton.singletonFactory.getInstance();  
  21.     }  
  22. }  
  23.   
  24. class MySingleton{//须要获实现单例的类,好比数据库链接Connection  
  25.     public MySingleton(){}   
  26. }  

验证单例实现的代码以下:

 

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. package org.mlinge.s10;  
  2.   
  3. public class MyThread extends Thread{  
  4.       
  5.     @Override  
  6.     public void run() {   
  7.         System.out.println(ClassFactory.getInstance().hashCode());  
  8.     }  
  9.       
  10.     public static void main(String[] args) {   
  11.           
  12.         MyThread[] mts = new MyThread[10];  
  13.         for(int i = 0 ; i < mts.length ; i++){  
  14.             mts[i] = new MyThread();  
  15.         }  
  16.           
  17.         for (int j = 0; j < mts.length; j++) {  
  18.             mts[j].start();  
  19.         }  
  20.     }  
  21. }  

验证结果:

 

 

[java]  view plain  copy
 
 print?在CODE上查看代码片派生到个人代码片
  1. 1935123450  
  2. 1935123450  
  3. 1935123450  
  4. 1935123450  
  5. 1935123450  
  6. 1935123450  
  7. 1935123450  
  8. 1935123450  
  9. 1935123450  
  10. 1935123450  

验证结果代表,完善后的单例实现更为合理。

 

以上就是本文要介绍的全部单例模式的实现,相信认真阅读的读者都已经明白文章开头所引入的那几个问题了,祝你们读得开心:-D!

 

备注:本文的编写思路和实例源码参照《Java多线程编程核心技术》-(高洪岩)一书中第六章的学习案例撰写。

相关文章
相关标签/搜索