java单例 同步 多线程

Java单例设计模式,多线程下同步


单例模式的特点:

  1. 只创建一次
  2. 私有的属性
  3. 公有的访问方法

单例模式的分类:

  1. 懒汉(LazySingleton);默认不自动实例化,等到用的时候根据当前情况实例化,并且返回当前对象;
  2. 恶汉(EagerSingleton);在类第一次加载的时候强制实例化;

用处:

         一般用在配置文件的读取,有些东西只需要加载一次,以后重复使用。

示例代码:

  1. package myThread;  
  2.   
  3. /** 
  4.  * 单例模式,懒汉模式 
  5.  *  
  6.  * @author Champion.Wong 
  7.  *  
  8.  */  
  9. public class LazySingleton {  
  10.   
  11.     private static LazySingleton singleton = null;  
  12.   
  13.     /** 
  14.      * 私有的构造方法,防止被多次实例化 
  15.      *  
  16.      */  
  17.     private LazySingleton() {  
  18.     }  
  19.   
  20.     /** 
  21.      * 静态工厂,返回此类的唯一一个实例 判断,如果没有被实例化,则先初始化再返回 
  22.      *  
  23.      * @return LazySingleton 
  24.      */  
  25.     public static LazySingleton getInstance() {  
  26.         if (null == singleton)  
  27.             singleton = new LazySingleton();  
  28.         return singleton;  
  29.     }  
  30. }  

  1. package myThread;  
  2.   
  3. /** 
  4.  * 单例模式,饿汉模式 
  5.  * @author Champion.Wong 
  6.  * 
  7.  */  
  8. public class EagerSingleton {  
  9.   
  10.     private static EagerSingleton singleton = new EagerSingleton(); // 强制初始化,在类加载的时候就创建好了对象  
  11.   
  12.     /** 
  13.      * 私有的构造方法,防止被多次实例化 
  14.      *  
  15.      */  
  16.     private EagerSingleton() {  
  17.     }  
  18.   
  19.     public static EagerSingleton getInstance() {  
  20.         return singleton;  
  21.     }  
  22. }  

前边说过了,单例只创建一次,来做个测试,在单例的类中加入一个属性,当这个类在实例化的时候,会将当前的时间赋给这个属性。我们创建两个单例类的对象,然后分别拿出它们类中的这个属性进行对比。

所以,在EagerSingleton中加入属性:createdTime

  1. package myThread;  
  2.   
  3. /** 
  4.  * 单例模式,饿汉模式 
  5.  * @author Champion.Wong 
  6.  * 
  7.  */  
  8. public class EagerSingleton {  
  9.   
  10.     private static EagerSingleton singleton = new EagerSingleton(); // 强制初始化,在类加载的时候就创建好了对象  
  11.   
  12.     /** 
  13.      * 私有的构造方法,防止被多次实例化 
  14.      *  
  15.      */  
  16.     private EagerSingleton() {  
  17.         createdTime = System.currentTimeMillis();  
  18.     }  
  19.   
  20.     public static EagerSingleton getInstance() {  
  21.         return singleton;  
  22.     }  
  23.       
  24.     private long createdTime = 0L; //此类的创建时间,在类实例化的时候赋值  
  25.     public long getCreatedTime() {  
  26.         return createdTime;  
  27.     }  
  28. }  

然后,写个Test:
  1. package myThread;  
  2.   
  3. public class Test_Singleton {  
  4.   
  5.     public static void main(String[] args) {  
  6.         EagerSingleton singleton1 = EagerSingleton.getInstance();  
  7.         try {  
  8.             Thread.sleep(2000); //让当前线程睡眠2000ms,这样,两个对象实例化的时间就差2s  
  9.         } catch (InterruptedException e) {  
  10.             e.printStackTrace();  
  11.         }  
  12.         EagerSingleton singleton2 = EagerSingleton.getInstance();  
  13.           
  14.         System.out.println("Singleton1:" + singleton1.getCreatedTime());  
  15.         System.out.println("Singleton2:" + singleton2.getCreatedTime());  
  16.     }  
  17.   
  18. }  

最后控制台输出的内容为:

两个对象的实例化的时间相同,证明单例设想成功!


当多个线程访问单例类的时候,必须要保证同时只能由一个线程访问,当这个线程访问结束了,其它线程才能访问。这是就要给单例的访问方法加个同步锁(synchronized)。

修改后的LazySingleton为:

  1. package myThread;  
  2.   
  3. /** 
  4.  * 单例模式,懒汉模式 
  5.  *  
  6.  * @author Champion.Wong 
  7.  *  
  8.  */  
  9. public class LazySingleton {  
  10.   
  11.     private static LazySingleton singleton = null;  
  12.   
  13.     /** 
  14.      * 私有的构造方法,防止被多次实例化 
  15.      *  
  16.      */  
  17.     private LazySingleton() {  
  18.     }  
  19.   
  20.     /** 
  21.      * 静态工厂,返回此类的唯一一个实例 判断,如果没有被实例化,则先初始化再返回 
  22.      *  
  23.      * @return LazySingleton 
  24.      */  
  25.     synchronized public static LazySingleton getInstance() {  
  26.         if (null == singleton)  
  27.             singleton = new LazySingleton();  
  28.             System.out.println(Thread.currentThread().getName() + System.currentTimeMillis());  
  29.         try {  
  30.             Thread.sleep(900); //假设每个线程访问的时候都需要耗费一定的时间  
  31.         } catch (InterruptedException e) {  
  32.             e.printStackTrace();  
  33.         }  
  34.         return singleton;  
  35.     }  
  36. }  

做个测试,起两个线程,没个线程中分别调用单例类的访问方法,每次访问的时候输出访问的时间,判断时间是否相等。如果相等,同步失败,如果不等,同步成功!
  1. package myThread;  
  2.   
  3. public class Test_Thread_Singleton {  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.     public static void main(String[] args) {  
  9.         SingletonThread st = new SingletonThread();  
  10.         SingletonThread st1 = new SingletonThread();  
  11.         st.start();  
  12.         st1.start();  
  13.     }  
  14.   
  15. }  
  16.   
  17. class SingletonThread extends Thread {  
  18.     private LazySingleton singleton = null;  
  19.     public void run() {  
  20.         while (!this.isInterrupted()) {  
  21.             try {  
  22.                 Thread.sleep(1000);  
  23.             } catch (InterruptedException e) {  
  24.                 e.printStackTrace();  
  25.             }  
  26.             singleton = LazySingleton.getInstance();  
  27.         }  
  28.     }  
  29. }  

看控制台的输出内容:

时间差不多都不一致,同步成功!限制了同时访问
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值