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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© lpf870826 中级黑马   /  2015-1-10 13:40  /  1421 人查看  /  4 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 lpf870826 于 2015-1-10 13:52 编辑

       单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问他的全局访问点,通常我们可以让一个全局变量使得一个对象被访问,但他不能防止实例化多个对象。一个最好的办法就是,让类自身负责保存他的唯一实例。这个类可以保证没有其他实例可以被创建,并且他可以提供一个访问该实例的方法。
      所有类都有构造方法,不编码则系统默认生成空的构造方法,如重写构造方法,则默认的构造方法就会失效。


  1. public class Singleton {
  2.     /**
  3.      *利用一个静态变量记录Singleton类的唯一实例。如果没有“static”修饰,下面的
  4.      *getSingleton()方法不能引用非静态变量singleton。“volatile”修饰符
  5.      *保证了内存可见,即如果该变量有变化(这里的变化就是被实例化),
  6.      *多个线程能及时看到singleton变量的变化。
  7.      */
  8.     private volatile static Singleton singleton;
  9.     //构造私有的构造函数,只有在Singleton类内才可以调用
  10.     private Singleton() {}
  11.     //getSingleton()方法提供了一个全局访问点
  12.     public static Singleton getSingleton() {
  13.         //利用双重锁,首先检查实例是否已经创建,如果没有创建才进行同步,
  14.         //如果创建过就直接返回,不需要加锁。
  15.         //如果对整个方法使用synchronized加锁则会造成效率降低。
  16.         if (singleton == null) {
  17.             synchronized (Singleton.class) {
  18.                 /**
  19.                  *如果为空,就利用私有的构造函数产生一个Singleton实例并把它赋值到singleton
  20.                  *静态变量中
  21.                                  */               
  22.                 if (singleton == null) {
  23.                     singleton = new Singleton();
  24.                 }
  25.             }
  26.         }
  27.         //如果不为空,就表示之前已经创建过实例,并将singleton当做返回值
  28.         return singleton;
  29.     }

  30.     public void add() {
  31.         System.out.println("add");
  32.     }

  33.     public static void main(String[] args) {
  34.         //创建实例
  35.         Singleton sing = Singleton.getSingleton();
  36.         Singleton sing2 = Singleton.getSingleton();
  37.         sing.add();
  38.         sing2.add();
  39.         //用“==”判断实例是否指向相同对象
  40.         System.out.println("sing == sing2: " + (sing == sing2));
  41.     }
  42. }

  43. 运行结果:
  44. add
  45. add
  46. sing == sing2: true     //通过结果可以看出两个引用指向同一对象
复制代码

这是在同一个类中创建main()方法,如果在另外一个类中创建
  1. public class Singleton {
  2.     private volatile static Singleton singleton;
  3.     private Singleton() {}

  4.     public static Singleton getSingleton() {
  5.         if (singleton == null) {
  6.             synchronized (Singleton.class) {
  7.                 if (singleton == null) {
  8.                     singleton = new Singleton();
  9.                 }
  10.             }
  11.         }
  12.         return singleton;
  13.     }

  14.     public void add() {
  15.         System.out.println("add");
  16.     }
  17. }

  18. class MainTest {
  19.     public static void main(String[] args) {
  20.             /**
  21.             *语句不能通过编译,就保证了类的单一实例。
  22.             */
  23.             //Singleton test3 = Singleton.singleton;  
  24.             //getSingleton()方法时静态的,就可以在代码的任何地方使用Singleton.getSingleton()
  25.         Singleton test1 = Singleton.getSingleton();
  26.         Singleton test2 = Singleton.getSingleton();
  27.         //Singleton test4 = Singleton.singleton;
  28.         test1.add();
  29.         //test3.add();
  30.         System.out.println("test1 == test2: " + (test1 == test2));
  31.         //System.out.println("test3 == test4: " + (test3 == test4));
  32.         //System.out.println("test1 == test3: " + (test1 == test3));
  33.         //System.out.println("test1 == test4: " + (test1 == test4));
  34.     }
  35. }
  36. 运行结果:
  37. E:\test-git\Thread>javac Singleton.java
  38. //编译时会编译出两个class文件,因为main方法在MainTest.class中,所有运行时用java MainTest
  39. E:\test-git\Thread>java MainTest
  40. add
  41. test1 == test2: true
复制代码


“private volatile static Singleton singleton”中的private修饰符如果该为public就不能保证类的唯一实例。
  1. public class Singleton {
  2.     public volatile static Singleton singleton;
  3.     private Singleton() {}

  4.     public static Singleton getSingleton() {
  5.         if (singleton == null) {
  6.             synchronized (Singleton.class) {
  7.                 if (singleton == null) {
  8.                     singleton = new Singleton();
  9.                 }
  10.             }
  11.         }
  12.         return singleton;
  13.     }

  14.     public void add() {
  15.         System.out.println("add");
  16.     }
  17. }

  18. class MainTest {
  19.     public static void main(String[] args) {
  20.             Singleton test3 = Singleton.singleton;  
  21.             //getSingleton()方法时静态的,就可以在代码的任何地方使用Singleton.getSingleton()
  22.         Singleton test1 = Singleton.getSingleton();
  23.         Singleton test2 = Singleton.getSingleton();
  24.         Singleton test4 = Singleton.singleton;
  25.         test1.add();
  26.         //test3.add();   如果加上运行时会报异常,引用了空指针
  27.         System.out.println("test1 == test2: " + (test1 == test2));
  28.         System.out.println("test3 == test4: " + (test3 == test4));
  29.         System.out.println("test1 == test3: " + (test1 == test3));
  30.         System.out.println("test1 == test4: " + (test1 == test4));
  31.     }
  32. }

  33. 运行结果:
  34. add
  35. test1 == test2: true   // 从这看出test1和test2是指向同一个对象的
  36. test3 == test4: false   // 从下面三句可以看出test3和test1、test2、test4的引用不同。
  37. test1 == test3: false   //从“test3.add();”看出test3为null。
  38. test1 == test4: true
复制代码

PS:我朋友说单例模式这才刚刚入门,还有两点更高级的东西,等进了水平高了再教。



4 个回复

倒序浏览
写得好,谢谢分享,收藏一下
回复 使用道具 举报
个人觉得单例模板和框架有点类似
回复 使用道具 举报
执笔画梦 来自手机 中级黑马 2015-1-10 17:45:28
板凳
有点复杂
回复 使用道具 举报
已收藏,感谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马