单件模式是设计模式里面最简单的模式。
它的目的是设计出只有一个实例的类,并确保全局访问。
经典单件模式
public static class singleton{
private singleton unique;
private singleton(){}
public static singleton getInstance(){
if(unique==null){
unique=new singleton();
}
return unique;
}
}
经典单件模式线程是不安全的。
static的用法
1. 静态方法
静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法 (就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。因为实例成员与特定的对象关联!
2. 静态变量
按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量。两者的区别是:
对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。
对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。
线程安全的单件模式
1. 同步getInstance()方法
public static synchronized getInstance()
优点:方便,缺点:效率低
2. 急切实例化
private static singleton unique=new singleton();
3.双重检查加锁
public class singleton{
private volatile static singleton unique;
private singleton(){}
public static singleton getInstance(){
if (unique==null){
synchronized(singleton.class){
if(unique==null){
unique=new singleton();
}
}
}
return unique;
}
}
volatile用法
当一个变量定义为 volatile 之后,将具备两种特性:
1.保证此变量对所有的线程的可见性,这里的“可见性”是,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存(详见:Java内存模型)来完成。
2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)。