(一) 什么是设计模式?
是一套被世人反复使用的,多数人知晓的,经过分类的代码设计经验的总结。
将实战项目比作一场战争的话,设计模式就是孙子兵法的三十六计。
(二) 设计模式的目的是什么?
保证代码的重用,让代码能够更容易被他人理解,保证代码的可靠性。
(三) 设计模式有哪些?
Java中,基本模式有23中,最常见的有单例模式、工厂模式、抽象工厂模式、建造者模式等。
(四) 单例模式的介绍
有些对象我们只需要一个,比如配置文件、工具类、线程池、缓存和日志文件等。如果创建出很多实例可能会出现很多问题,如占用太多资源、不一致等问题。
保证对象或者实例只有一个呢?靠单例来实现。
单例模式的两种模式——饿汉模式和懒汉模式
饿汉模式:
第一步,在类中将默认构造函数变为private()类型,不允许外部创建此类的对象;
private Singleton(){}
第二步,在类中定义一个类的对象,且类型定义为static ;
staticSingleton instance = new Singleton();
通过类名.instance即可获取单例。
但是我们又要保证其安全性,所以我们再把单例定义为private类型的
private staticSingleton instance = new Singleton();
第三步,提供一个获取实例的方法
public staticSingleton getInstance(){
return instance;
}
类名打点调用即可获取实例。
那么,饿汉模式体现在那里呢?实例是static类型的,当类被加载的时候,这个实例也被加载了,不管这个实例有没有被使用,它要早先吃饱。
懒汉模式:
第一步,在类中将默认构造函数变为private()类型,不允许外部创建此类的对象;
private Singleton(){}
第二步,声明一个对象
private staticSingleton instance ;
第三步,提供一个获取实例的方法,注意非空判断
public Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
懒汉模式体现在哪里呢?我们注意到,它是只先声明的,当我们使用的时候才会初始化它。
懒汉模式和饿汉模式有什么区别呢?
饿汉模式类加载比较慢(类加载时要加载对象),但它运行时获取对象的速度比较快。且线程安全。
懒汉模式正好相反。
懒汉模式线程不安全主要是因为“判断是否创建了这个实例”的代码块没有加同步代码块也没有加判断,即没有双重检查锁定。
首先,什么是同步代码块呢?
我们先来了解一下synchronized修饰的方法,如果某对象的一个方法需要在线程之间保持同步,那么需要定义为synchronized类型的方法,来保证一次只有一个线程调用这个方法。
具体是指只要一个线程访问了某个对象的一个synchronized修饰的方法,那么其他线程就不能同时再访问这个对象的其他任何synchronized修饰的方法。当然,其他线程可以去访问其他对象的方法嘛,这个不影响。
但这样往往会产生效率低下的问题,因为可能某个函数只是其中一部分代码的执行需要在线程中保持同步,而我们用了synchronized修饰方法后,会让线程等待的次数增多,效率变低。因此这时就出现了同步代码块,它只对某个函数中的一部分进行限制。
我们总结一下同步代码块和同步方法的区别:
1. 尺寸上讲,同步代码块更小,更灵活。
2. 同步代码块可以指定其他调用此方法的方式,导致了某个线程可以一直霸占着调用这个方法。
(具体可以参考http://blog.csdn.net/yclzh0522/article/details/7295914)
因此,我们可以使用同步锁机制来解决线程同步问题,但同时在多线程并发访问的情况下,每个线程每次获取实例时都要进行锁判断,效率比较低,因此我们再加一重判断,使之只在第一次判断实例没有初始化后进行初始化(这样也就构成了上面所说的双重检查锁定)。
1. public class SingleDemo {
2. private static SingleDemo s = null;
3. private SingleDemo(){}
4. public static SingleDemo getInstance(){
5. /*如果第一个线程获取到了单例的实例对象,
6. * 后面的线程再获取实例的时候不需要进入同步代码块中了*/
7. if(s == null){
8. //同步代码块用的锁是单例的字节码文件对象,且只能用这个锁
9. synchronized(SingleDemo.class){
10. if(s == null){
11. s = new SingleDemo();
12. }
13. }
14. }
15. return s;
16. }
17. }
PS:实际开发中,还是饿汉模式使用的多,毕竟懒汉模式的代码太过繁琐。