单例模式定义
Ensure a class has only one instance, and provide a global point of access to it.
也就是说:确保某一个类只有一个实例, 而且自行实例化并向整个系统提供这个实例。
单例模式的类图
单例模式的分类
单例模式可分为,饿汉式和懒汉式
饿汉式
饿汉式顾名思义,迫不及待的就new一个对象出来,不管你要不要,我自己先实例化一个实例再说,你需要的时候我就给你,不需要的话就放我这.
懒汉式
而懒汉式呢,就是当你第一次需要的时候我才去实例化,你不要我就不实例化
这两种方式有什么特点呢,首先饿汉式在类加载的时候会比较慢,为什么呢,因为类在加载的时候首先要去实例化一个对象,实例化对象肯定比较耗时,但是在获取实例的时候会比较快,毕竟人家已经实现实例化好了,就等着你用了.
懒汉式呢,在类加载的时候会比较快,但是在第一次获取实例的时候会比较慢,原因在于,第一次获取实例的时候,它需要去先实例化,再返回给别人.而且呢,饿汉式是线程安全的,懒汉式是线程不安全的,为什么这么说,试想一下,在高并发的情况下,假设A需要去获取一个实例,在判断是否存在该实例时,返回null,所以这是需要去创建一个实例,但是它还没创建完,这时B也想要一个实例,他也去判断是否存在,结果判断结果也不存在,因为A在获取的时候还没有实例化完成,B就来要了,所以这时候就会产生2两个实例,所以说是线程不安全的
饿汉式代码
/**
*@DESCRIPTION 饿汉式单例模式
*@AUTHOR SongHongWei
*@TIME 2018/8/12-19:14
*@PACKAGE_NAME test.factory.single
**/
public class Singleton
{
//new一个实例
private static Singleton instance = new Singleton();
//构造方法私有化
private Singleton()
{
}
//对外提供一个实例对象
public static Singleton getInstance()
{
return instance;
}
//计数器
private int count;
//计数器方法
public int addCount()
{
return ++count;
}
}
懒汉式代码
/**
*@DESCRIPTION 懒汉式单例模式
*@AUTHOR SongHongWei
*@TIME 2018/8/12-19:14
*@PACKAGE_NAME test.factory.single
**/
public class Singleton
{
//new一个实例
private static Singleton instance ;
//构造方法私有化
private Singleton()
{
}
//对外提供一个实例对象
public static Singleton getInstance()
{
if (instance==null)
instance = new Singleton();
return instance;
}
//计数器
private int count;
//计数器方法
public int addCount()
{
return ++count;
}
}
客户端模拟调用计数器
public class Client
{
public static void main(String[] args)
{
int count = 0;
Singleton instance = Singleton.getInstance();//获取实例
for (int i = 0; i < 10; i++)
{
count = instance.addCount();//模拟调用10次计数
}
System.out.println("count====" + count);
Singleton instance2 = Singleton.getInstance();//模拟另一处地方获取该实例并调用计数器方法
count = instance2.addCount();//
System.out.println("count====" + count);//如果两处地方获取的不是同一个实例,那么第二次获取的对象count值应该为1,否则为11
}
}
输出结果
count====10
count====11
Process finished with exit code 0
客户端模拟懒汉式线程不安全情况
/**
*@DESCRIPTION 模拟调用单例模式的计数器场景
*@AUTHOR SongHongWei
*@TIME 2018/8/12-19:16
*@PACKAGE_NAME test.factory.single
**/
public class Client
{
public static void main(String[] args)
{
int count = 0;
//模拟高并发,同时启动9999个线程
for (int i = 0; i < 9999; i++)
{
Thread thread = new Thread(new Single());
thread.start();
}
}
}
//调用计数器的线程
class Single implements Runnable
{
@Override
public void run()
{
Singleton instance = Singleton.getInstance();//获取实例
System.out.println("count====" + instance.addCount());
}
}
输出结果
count====1
count====3
count====4
count====2
count====1
count====5
count====6
count====7
count====8
count====9
明显看出结果有两处打印的是1,也就是说实例化了2个对象
适用场合
- 需要频繁的进行创建和销毁的对象;
- 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
- 工具类对象;
- 频繁访问数据库或文件的对象。