总体来说分三大类:
单例设计模式
- 对本类构造方法私有化,防止外部调用构造方法创建对象
- 创建全局唯一的对象,也做私有化处理
- 通过自定义的公共方法将创建好的对象返回(类似封装属性后的getXxx() )
饿汉式:
package cn.tedu.design;
/*本类用于测试单例设计模式 1 - 饿汉式*/
public class Singleton1 {
public static void main(String[] args) {
//6.通过类名调用getSingle()方法获取本类对象
MySingle single1 = MySingle.getSingle();
MySingle single2 = MySingle.getSingle();
//7.测试获取到的这两个引用类型变量是否相等
System.out.println(single1 == single2);//true,==比较的是地址值,说明是同一个对象
System.out.println(single1);//cn.tedu.single.MySingle@1b6d3586
System.out.println(single2);//cn.tedu.single.MySingle@1b6d3586
}
}
//0.创建自己的单例程序
class MySingle{
//1.提供构造方法,并将构造方法私有化
/*1.构造方法私有化的目的:为了不让外界随意实例化/new本类对象*/
private MySingle(){ };
/*3.思考:构造方法和对象私有化后,通过公共的访问点来获取对象,那外界如何调用这个公共方法呢?
* 之前我们都是在外部创建本类对象并进行方法调用,但是现在单例程序中外部无法直接创建本类对象
* 解决方案:我们可以利用之前学习的静态的概念,将方法修饰成静态的,就可以通过类名直接调用啦
* 注意事项:静态只能调用静态,所以静态方法中返回的对象也需用静态修饰*/
//2.在类的内部,创建本类对象,并且私有化
//5.2本资源也需要使用static修饰,因为静态方法getSingle()只能调用静态资源
static private MySingle single = new MySingle();
/*2.也就是以公共的方式向外界提供获取本类私有对象的方法*/
//3.对外提供一个公共的全局访问点
//5.1用static关键字来修饰本方法,为了外部可以通过类名直接调用本方法
static public MySingle getSingle(){
//4.把内部创建好的对象返回到调用位置,谁调用这个方法,谁就能拿到返回的single对象
return single;
}
}
懒汉式:
package cn.tedu.single;
/*本类用于测试单例设计模式 2 - 懒汉式--面试重点!!!*/
/*总结:
* 关于单例设计模式的两种实现方式:
* 1.饿汉式 : 不管你用不用这个类的对象,都会直接先创建一个
* 2.懒汉式 : 先不给你创建这个类的对象,等你需要的时候再帮你创建--利用了延迟加载的思想
* 延迟加载的思想:是指不会在第一时间就把对象创建好来占用内存,而是什么时候用到,什么时候再去创建对象
* 3.线程安全问题 : 是指共享资源有线程并发的数据安全隐患,可以通过加锁的方式[同步代码块/同步方法]
* */
public class Singleton2 {
public static void main(String[] args) {
//6.创建对象进行测试
MySingle2 s1 = MySingle2.getMySingle2();
MySingle2 s2 = MySingle2.getMySingle2();
System.out.println( s1 == s2 );//true,比较的是地址值,说明是同一个对象
System.out.println( s1 );//cn.tedu.single.MySingle2@1b6d3586
System.out.println( s2 );//cn.tedu.single.MySingle2@1b6d3586
}
}
//0.创建单例程序
class MySingle2{
//1.私有化构造方法,为了防止外部调用构造方法直接创建本类对象
private MySingle2(){}
//2.在类的内部创建好引用类型变量(延迟加载的思想)--注意私有化
//5.2本处的引用类型变量也需要修饰成static的,因为静态只能调用静态,getMySingle2()是静态方法
static private MySingle2 single2;
//7.2.2同步代码块中使用的唯一的锁对象
static Object o = new Object();
/*问题:程序中有共享资源single2,并且有多条语句(3句)操作了共享资源
* 此时single2共享资源在多线程环境下一定会存在多线程数据安全隐患
* 解决方案1:同步代码块[加锁,范围是操作共享资源的所有代码]
* 解决方案2:同步方法[如果方法中的所有代码都需要被同步,那么这个方法可以修饰成同步方法]
* 注意事项:锁对象在静态方法中,不可以使用this,因为静态资源优先于对象加载
* 锁对象可以使用外部创建好的唯一的锁对象o,但请注意,需要是静态的,静态只能调用静态
* */
//3.对外提供公共的全局访问点
//5.1注意要使用static来修饰本公共方法,为了方便后续可以通过类名直接调用
//7.1将方法修饰成同步方法
synchronized static public MySingle2 getMySingle2(){
//4.当用户调用此方法时,才说明用到这个对象了,那么我们就把这个对象返回
/*注意:这里需要增加一个判断
如果调用方法时single2的值为null,说明之前没有new过,保存的是默认值
这时才需要new对象,如果single2的值不为null,直接return single2即可*/
//7.2可以将操作共享资源的多条语句放入同步代码块之中
synchronized (o) {
//synchronized (this) {
if (single2 == null) {
single2 = new MySingle2();//没有对象时才创建对象,并赋值给single2
}
return single2;//有对象则直接返回single2
}
}
}