一、 单例模式
1.什么是单例模式
在所有的设计模式中,单例模式是我们在项目开发中最为常见的设计模式之一,单例模式确保一个类只有一个实例,并且提供一个全局访问点。单利模式只有一个私有的构造器,一个静态方法。私有构造器保证无法在其他类中对本类进行实例化,静态方法则以类名+方法名的方式对其他类提供访问权限。单例对象的生命周期从创建初始直到程序结束为止。
2.单利模式的应用场景
单利模式适用于在程序中需要且仅需要一个的对象。例如:线程池,缓存,注册表对象,日志对象,打印机驱动对象等。拿打印机驱动对象来说,一个系统中可以存在多个打印任务,如果存在多个打印对象执行打印方法,所打印的文件内容就极有可能串掉,但如果只有一个正在工作的任务,依次打印,则完全不会串掉。
3.懒汉式单例模式
懒汉式单例模式指的是在要用的时候才会去创建,代码如下:
package singleton;
/**
* @author zhangbj
* @version 1.0
* @Type SingleTonPattern
* @Desc
* @data 2017/6/27
*/
public class SingleTonPattern {
//懒汉式单例模式 SingleTonPattern对象在类加载时暂不创建
private static SingleTonPattern singleTonPattern;
//私有构造器
private SingleTonPattern(){
}
public static SingleTonPattern getInstance(){
//当SingleTonPattern要被用到的时候 开始创建
if (singleTonPattern == null){
singleTonPattern = new SingleTonPattern();
}
return singleTonPattern;
}
}
4.饿汉式单例模式
package singleton;
/**
* @author zhangbj
* @version 1.0
* @Type SingleTonPattern
* @Desc
* @data 2017/6/27
*/
public class SingleTonPattern {
//饿汉式单例模式 SingleTonPattern对象在类加载时就会创建
private static SingleTonPattern singleTonPattern = new SingleTonPattern();
//私有构造器
private SingleTonPattern(){
}
public static SingleTonPattern getInstance(){
return singleTonPattern;
}
}
5.单例模式的线程安全
单例模式最基本的特征就是保证系统内对象的唯一性,但是在多线程之下如何保证?
5.1. 线程不安全的单例模式
在多线程情况下,懒汉式单例模式表现出来不可靠性。如下:
我们先让懒汉式单利模式干点事:
package singleton;
/**
* @author zhangbj
* @version 1.0
* @Type SingleTonPattern
* @Desc
* @data 2017/6/27
*/
public class SingleTonPattern {
//懒汉式单例模式 SingleTonPattern对象在类加载时暂不创建
private static SingleTonPattern singleTonPattern;
private SingleTonPattern(){
}
public static SingleTonPattern getInstance(){
//当SingleTonPattern要被用到的时候 开始创建
if (singleTonPattern == null){
//do something
for (int index = 0; index <100000000;index++){
}
singleTonPattern = new SingleTonPattern();
}
return singleTonPattern;
}
}
测试类实现Runnable接口,然后测试多线程下的懒汉式单例模式。
package singleton;
import java.util.ArrayList;
import java.util.List;
/**
* Created by PC on 2017/6/27.
*/
public class SingleTonPatternTest implements Runnable{
@Override
public void run() {
//输出本类的hashcode以及单例对象的hashcode
System.out.println(this.hashCode() + "------" +SingleTonPattern.getInstance().hashCode());
}
public static void main(String[] args) {
//创建Thread的集合
List<Thread> list = new ArrayList<Thread>();
for (int index = 0;index < 10 ;index++){
//多态,使thread调用SingleTonPatternTest的run()方法
list.add(new Thread(new SingleTonPatternTest()));
}
//lambda表达式 thread.start()使线程处于就绪状态
list.forEach(thread -> thread.start());
}
}
结果:(前面的是循环创建测试累的hashcode,后面是懒汉单例模式的hashcode)
1938385570------2102303395
898432218------2102303395
834743824------1057408600
2115964816------1057408600
1888310064------1064810858
387638489------1064810858
551098425------1064810858
1229341769------1064810858
2099930026------1064810858
2107834669------1064810858
由此可见,这样的懒汉式单例设计模式线程是不安全的。但这时候我们可以利用双重检查加锁:
package singleton;
/**
* @author zhangbj
* @version 1.0
* @Type SingleTonPattern
* @Desc
* @data 2017/6/27
*/
public class SingleTonPattern {
//懒汉式单例模式 SingleTonPattern对象在类加载时暂不创建
//用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值
private volatile static SingleTonPattern singleTonPattern;
private SingleTonPattern(){
}
public static SingleTonPattern getInstance(){
//当SingleTonPattern要被用到的时候 开始创建
//同步块
synchronized (SingleTonPattern.class){
if (singleTonPattern == null){
for (int index = 0; index <100000000;index++){
}
singleTonPattern = new SingleTonPattern();
}
}
return singleTonPattern;
}
}
结果:
1912001919------1040985866
1888310064------1040985866
1741313022------1040985866
898432218------1040985866
1938385570------1040985866
387638489------1040985866
1554207314------1040985866
129515986------1040985866
834743824------1040985866
2115964816------1040985866