一. 概述
1. 设计模式
解决某一类问题最行之有效的方法。
Java中有23种设计模式。
2. 单例设计模式
实现一个类在内存只存在一个对象
想要保证对象唯一:
(1)为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象。
(2)为了让其他程序可以访问到该类对象,只好在本类中自定义一个对象。
(3)为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
用代码体现:
(1)将构造函数私有化。
(2)在类中创建一个本类对象【私有静态】。
(3)提供一个方法可以获取到该对象【公共静态】。
class Single
{
//构造函数私有化
private Single(){}
//呼应下一个函数,静态函数只能访问静态对象,用static修饰
//类变量一般私有化
private static Single s=new Single();
//如果不通过类对象调用,只能通过类调用,函数需要用static调用
public static Single getInstance()
{
return s;
}
}
三. 应用
class Single
{
private int num;
public void setNum(int num)
{
this.num=num;
}
public int getNum()
{
return num;
}
private Single(){}
//呼应下一个函数,静态函数只能访问静态函数
//类变量一般私有化
private static Single s=new Single();
//如果不通过类对象调用,只能通过类调用,函数需要用static调用
public static Single getInstance()
{
return s;
}
}
class SingleDemo
{
public static void main(String[] args)
{
Single s1=Single.getInstance();//通过类直接调用静态函数
Single s2=Single.getInstance();//通过类直接调用静态函数
s1.setNum(23);
System.out.println(s2.getNum());
}
}
四. 饿汉式和懒汉式
1. 饿汉式
单例对象一开始就被new Single()主动构建,则不再需要判空操作
class Single
{
private Single(){}
private static Single s=new Single();
public static Single getInstance()
{
return s;
}
}
“饿汉式”的优缺点:
优点:实现起来简单,没有多线程同步问题。
缺点:当类Single被加载的时候,会初始化static的s,静态变量被创建并分配内存空间,从这以后,这个static的s对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。
2. 懒汉式
单例初始值是null,还未构建,当需要被调用时才建立单例对象。
public class Single {
private static Single s = null;
private Single(){}
public static Single getInstance() {
if (s== null) {
//--A
//--B
//s是共享数据,多线程访问时会产生安全隐患,产生多个对象
s= new Single();
}
return s;
}
}
“懒汉式”的优缺点:
优点:实现起来比较简单,当类Single被加载的时候,静态变量static的s未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化s变量,并分配内存,因此在某些特定条件下会节约了内存。
缺点:在多线程环境中,这种实现方法是完全错误的,根本不能保证单例的状态。
3. 线程安全的懒汉式
用静态同步函数解决
public class Single {
private static Single s = null;
private Single(){}
// 静态方法返回该实例,加synchronized关键字实现同步
public static synchronized Single getInstance() {
if (s== null) {
s= new Single();
}
return s;
}
}
优点:在多线程情形下,保证了“懒汉模式”的线程安全。
缺点:多个线程,每个线程都要判断锁,比较低效
4. DCL双检查锁机制
DCL:double checked locking
用静态代码块+双重判断解决(因为该代码块在同步函数里面,锁要用Single.class对象)
减少锁粒度
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
// 第一次检查instance是否被实例化出来,如果没有进入if块
if(s==null)
{
// 某个线程取得了类锁,实例化对象前第二次检查instance是否已经被实例化出来,如果没有,才最终实例出对象
synchronized(Single.class)
{
if(s==null)
s = new Single();
}
}
return s;
}
}
内存占用率高,效率高,线程安全,多线程操作原子性。