Java中一共有23种设计模式,而单例设计模式作为其中最常见的一种,主要是为了解决一个类在内存中只存在唯一的对象或实例,其写法主要有两种:懒汉式单例(4种)、饿汉式单例
单例设计模式的实现:
①将类中的构造函数私有化,避免其他类中可以创建该类对象
②在本类中创建一个该类对象,进行实例化过程
③提供共有的静态方法供其他类来使用
1、饿汉式单例
在类加载,初始化的时候,单例对象便一起创建,占用了内存,但不存在线程安全问题
public class Sington {
private static final Sington instance = new Sington();
private Sington(){
}
public static Sington getInstance(){
return instance;
}
public void loadData(){
System.out.println("singleton data....");
}
}
2、懒汉式单例
类加载初始化的时候没有创建其实例对象,只有当调用getIntance()方法的时候,才会去实例化这个对象,提高了内存使用效率
public class Sington {
private static Sington instance = null;
private Sington(){
}
public static Sington getInstance(){
if(instance == null){
instance = new Sington();
}
return instance;
}
}
但上述实现单例的过程,存在这样的一种问题,当开启多线程来访问这个类对象,假设有两个线程A和B,当线程A执行到instance = new Sington() ,正在申请内存分配,可能需要0.001us,可就在这段时间内,线程B执行到 if(instance == null) ,这时条件为true,线程B继续往下执行,内存中便有了两个Sington 对象,出现了线程安全问题,为了解决这样的问题,一般我们采用以下四种方式来编写:
①在getInstance()方法上加同步,上this对象锁,保证线程之间互斥,但也因为锁对象影响了该方法的执行效率,毕竟大多数业务情况下是不存在并发执行的。
public class Sington {
private static Sington instance = null;
private Sington(){
}
public synchronized static Sington getInstance(){
if(instance == null){
instance = new Sington();
}
return instance;
}
}
②采用同步代码块+双重判断+votatile关键字保证线程安全,保证只有第一次进来的时候才会有同步锁,提高了效率,同时这里说一下多线程操作同一变量时,共享变量的安全性问题:多个线程在访问一个全局共享变量时,会先把变量从主存中加载到线程各自的工作内存中,然后在工作内存中进行操作,默认情况下,线程之间的变量修改是不可见的;当用volatile修饰变量后,一个线程执行此变量操作前会先和主存中的变量同步,同时修改后会同步刷新到主存中,保证线程之间变量修改的可见性
public class Sington {
private volatile static Sington instance = null;
private Sington(){
}
public static Sington getInstance(){
if(instance == null){
synchronized (Sington.class){
if(instance == null)
instance = new Sington();
}
}
return instance;
}
}
③静态内部类,利用classloader的加载机制保证类初始化对象时只有一个线程,既是线程安全的,同时又没有性能损耗,日常使用时推荐
public class Sington {
private static class LazyLoad{
private static Sington INSTANCE = new Sington();
}
private Sington(){
}
public static Sington getInstance(){
return LazyLoad.INSTANCE;
}
}
④枚举,在访问枚举实例的时候,会先执行构造方法,同时枚举中的属性都是static final类型的,也就表明intance只能被实例化一次,同时,枚举也提供了序列化机制,其实现了Serializable接口
public class Sington {
private enum LazyLoad{
INSTANCE;
private Sington instance;
LazyLoad(){
instance = new Sington();
}
}
private Sington(){
}
public static Sington getInstance(){
return LazyLoad.INSTANCE.instance;
}
}