A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© Enhon1992 中级黑马   /  2015-6-7 18:35  /  777 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

在Java开发中,有时我们会有这样的需求就是在描述一个类的时候,要求我们必须保证这个类的对象在内存中只会存在一个,就是保存对象在内存中的唯一性,那我们在设计这个类的时候,就应该使用单例设计模式。Java中常用的单例设计模式 有两种,懒汉式,饿汉式。采用单例设计模式设计的类有以下特点:
1,在该类中需要定义一个该类类型的静态字段。
2,将该类的构造函数私有化。
3,对外提供能够获取该类实例的静态工厂方法。

懒汉式:
  1. class Single
  2. {
  3.        
  4.                 //定义一个静态的私有字段
  5.                 private static Single s=null;
  6.                
  7.                
  8.                 //定义静态工厂方法 返回该类的实例
  9.                 public static Single getSingleInstance()
  10.                 {
  11.                         if(s==null)
  12.                         {       
  13.                                 s=new Single();
  14.                         }
  15.                         return s;
  16.                 }
  17.                
  18.                 //私化构造函数
  19.                 private Single()
  20.                 {
  21.                        
  22.                 }
  23. }
复制代码

饿汉式:
  1. class Single
  2. {
  3.        
  4.                 //定义一个静态的私有字段, 并在类加载时候就创建了该类的实例
  5.                 private static final Single s=new Single();
  6.                
  7.                
  8.                 //定义静态工厂方法 返回该类的实例
  9.                 public static Single getSingleInstance()
  10.                 {
  11.                         return s;
  12.                 }
  13.                
  14.                 //私化构造函数
  15.                 private Single()
  16.                 {
  17.                        
  18.                 }
  19. }
复制代码

懒汉式和饿汉式的区别:
1,饿汉式是在类加载的时候内存中就创建了对象,而懒汉式 是在调用该类的静态工厂方法的时候才创建对象。
2,饿汉式 是线程安全的,而懒汉式线程不安全。

分析懒汉式产生线程安全问题的原因:
当多个线程同时 执行懒汉式中的getSingleInstance()方法的时,这多个线程都会访问共享数据 静态私有字段s(因为该字段是静态的  所以是共享数据),并且操作共享数据的代码是多行,所以会产生线程安全问题,这样就保证不了该类在内存中的对象的唯一性。

解决懒汉式线程安全问题:
  1. class Single
  2. {
  3.        
  4.         //定义一个静态的私有字段
  5.         private static Single s=null;


  6.         //定义静态工厂方法 返回该类的实例
  7.         public static Single getSingleInstance()
  8.         {
  9.                 if(s==null)
  10.                 {       
  11.                         synchronized(Single.class)
  12.                         {
  13.                                 if(s==null)
  14.                                 {
  15.                                         s=new Single();
  16.                                 }
  17.                         }
  18.                        
  19.                 }
  20.                 return s;
  21.         }
  22.        
  23.         //私化构造函数
  24.         private Single()
  25.         {
  26.        
  27.         }
  28. }
复制代码

上面两种单例模式,能够保证对象的唯一性的根本原因就是 ,将构造函数私有化,不允许在该类的外部调用构造函数创建对象。要是我们利用反射技术Single.class.getDeclaredConstructor(null).setAccessible(true); 来获取到该类构造器对象 ,那么这样的话就保证不了对象的唯一性。所以说我们要是利用反射技术的话,上面两种单例模式就会失效。

PS:如果一个枚举类的枚举值只有一个话,这个枚举类可以当做单例设计模式使用。

评分

参与人数 1技术分 +1 收起 理由
lwj123 + 1

查看全部评分

7 个回复

正序浏览
学习了~~~~
回复 使用道具 举报
很给力 ,赞一个
回复 使用道具 举报
饿汉式单例设计模式存在线程安全问题,应该双重判断,利用同步代码块的形式来保证多线程下饿汉式的安全问题
下面这个是我写的代码,不知大家认同不,小菜鸟,写的不对的,望大家指教
package com.itheima;
/**
* 题目8:编写一个延迟加载的单例设计模式。
* @author xiaocheng
*
*/
public class Test8 {

        /**
         * @param args
         */
        public static void main(String[] args) {
               
                /**
                 * 通过本类对象调用getSingleInstance()方法来获取本类对象
                 * 而不能通过new的方式来产生本类对象,保证了本类对象的唯一性
                 */
                Single s1 = Single.getSingleInstance();                //通过本类对象调用getSingleInstance()方法来获取本类对象s1
                Single s2 = Single.getSingleInstance();                //通过本类对象调用getSingleInstance()方法来获取本类对象s2
               
                //如果打印结果为true,则说明s1和s2是同一个对象,如果打印结果为false,则说明s1和s2是两个不同的对象
                System.out.println("s1==s2:"+(s1==s2));
        }

}

/**
* 定义一个延迟加载的单例设计模式
* 单例设计模式的实现:
* 1.构造函数私有化
* 2.在本类中创建一个私有的本类对象
* 3.提供一个方法可以获取到本类对象
* 单例设计模式分为懒汉式和饿汉式
* 其中延迟加载属于懒汉式
* 懒汉式在多线程中容易出现安全问题,所以需要使用synchronized同步代码块,保证多线程的安全问题
*/
class Single{
       
        private Single(){}                //构造函数私有化
        private static Single s = null;        //在本类中创建一个私有的本类对象
        public static Single getSingleInstance()
        {
                /**
                 * 因为懒汉式在多线程中容易出现安全问题,
                 * 所以需要使用synchronized给代码块加锁,保证多线程的安全问题
                 * 这里的锁是本类的字节码文件Single.class
                 */
                if(s==null)
                {
                        synchronized (Single.class) {
                                s = new Single();
                        }
                }       
                return s;
        }
}
回复 使用道具 举报
很不错啊
回复 使用道具 举报
这块自学一直没怎么学懂,还得继续研究才行.
回复 使用道具 举报
storer 发表于 2015-6-7 19:05
后面的没有听懂啊,还要继续学习

你说反射那块啊!
回复 使用道具 举报
后面的没有听懂啊,还要继续学习
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马