1:单例模式(面试)
单例模式:单一的实例.保证类在内存中只有一个对象.
举例:
①windows的打印费服务.网站的计数器.(如果一个网站统计访问量有多个计数器,就会有问题.)
②Java中的应用:数据库连接池,Runtime这个类.
2.如何保证类在内存中只有一个对象?
A:把构造方法私有,为了不让外界创建对象.
B:在类中创建 一个对象.(有一个对象,还是要创建它)
C:通过一个公共的访问方式,给外界一个入口.(否则外界根本就无法访问到)
3.饿汉式单例模式:
Student.java
1 public class Student { 2 //为了不让外界访问,我们把构造方法私有. 3 private Student(){ 4 5 } 6 //创建一个对象 7 //为了满足静态方法访问,这里也必须加一个静态修饰符static(暂时先不加private,慢慢引入private) 8 //static Student s = new Student(); 9 private static Student s = new Student(); 10 11 //提供一个公共的访问方式 12 //(访问这个方法可以通过Student类的对象,但是构造方法私有化了无法让外界访问) 13 //所以为了让外界直接访问,只能让这个方法静态. 14 public static Student getStudent(){ 15 //比如说我有t1和t2同时来访问,那么这个时候.拿的都是上面new的 17 return s; 18 //如果此时上面的Student s = new Student();不用静态修饰,报错.内容如下 19 //Cannot make a static reference to the non-static field s 20 //一个静态的上下文,不能有一个非静态的变量. 21 //所以为了满足静态方法访问,new Student的时候必须用static修饰. 22 } 23 24 public void show(){ 25 System.out.println("我爱java"); 26 } 27 }
测试类:StudentTest.java
1 public class StudentTest { 2 public static void main(String[] args) { 3 /* 4 Student s1 = new Student(); 5 Student s2 = new Student(); 6 System.out.println(s1 == s2);//false 7 */ 9 //由于成员变量是被静态static修饰的,前面没有加访问修饰符,默认是default外界也可以通过类名访问的. 10 //Student.s = null; 11 //这样的话下面运行s1.show()的时候就会报java.lang.NullPointerException 12 //为了不让外界访问s,就再在new 的时用private修饰. 这样此时 13 14 //通过单例模式获取对象并调用方法. 15 16 Student s1 = Student.getStudent(); 17 Student s2 = Student.getStudent(); 18 System.out.println(s1 == s2);//true 19 20 s1.show(); 21 s2.show(); 22 } 23 }
4:懒汉式单例模式(想用的时候再用)
懒汉式有一个非常重要的思想----延迟加载思想.
我们什么时候需要,你就什么时候给. 这个思想在Hibernate和Spring中都用了这个思想. 特别是Hibernate框架中的lazy....
Teacher.java
1 public class Teacher { 2 // 为了不让外界创建对象,把构造方法私有. 3 private Teacher() { 4 } 5 6 // 本类创建一个对象. 7 // 加static是为了保证静态方法可以访问. 8 // 加private是为了保证外界不能直接访问 9 private static Teacher t = null; 10 11 // 提供公共的访问方式. 12 //synchronized是为了解决懒汉式多线程不安全加上的. 13 //被同步的代码,在某一时刻只能被一个线程访问. 14 public synchronized static Teacher getTeacher() { 15 /* 16 比如说我有t1和t2同时来访问,那么这个时候. 17 当t1进来后,判断这个时候t是null 18 所以,t1就进去执行if所控制的语句. 19 但是注意了,由于线程的随机性.可能当t1刚进去要执行if说控制的语句. 20 发现,这个时候t还是null,所以,t2也去执行if所控制的语句了. 21 那么将来就会有多个对象被创建. 22 */ 23 // 当外界需要使用它,就在这里new一个. 24 if (t == null) { 25 // 只有第一次访问这里的时候才进入if语句new一个对象. 26 // 第二次的时候因为第一次已经new了一个Teacher,并且Teacher是用static修饰 27 // static修饰的是共享的.有值了,就不再进入if了. 28 t = new Teacher(); 29 } 30 return t; 31 } 32 33 // 写了一个方法 34 public void love() { 35 System.out.println("老师爱学生"); 36 } 37 }
TeacherTest.java
1 public class TeacherTest { 2 public static void main(String[] args) { 3 Teacher t1 = Teacher.getTeacher(); 4 Teacher t2 = Teacher.getTeacher(); 5 System.out.println(t1 == t2);// true 6 7 t1.love(); 8 t2.love(); 9 } 10 }
5:那么我们在开发中到底使用谁呢?
一般开发中使用第一种方案(饿汉式)
原因是:
前提:多线程安全问题.
面试的时候会面试懒汉式. 并且,请注意,面试懒汉式,主要是面试下面几个问题:
A:延迟加载思想.
B:线程安全问题.
a:线程安全问题是怎么产生的.
b:线程安全问题是怎么解决的.
6:其实在JDK中提供的类中,已经有单例模式的应用.是谁呢?Runtime类.
附上JDK中关于Runtime类的源码:
Runtime.java
1 public class Runtime { 2 //这就是一个饿汉式的应用. 3 private static Runtime currentRuntime = new Runtime(); 4 5 public static Runtime getRuntime() { 6 return currentRuntime; 7 } 8 9 private Runtime() {} 10 11 }