Java中创建对象的方式
直接调用构造方法
利用反射调用构造方法
反序列化
克隆
Unsafe实现对象的创建
1:构造方法私有饿汉式单例模式,
/*
* 饿汉式单例模式
*
* 缺点:Unsafe方式现在不好预防
*
*/
class Single01 implements Serializable {
private Single01() {
if (SingleTon!=null){
//防止反射破坏单例模式
throw new RuntimeException("请不要试图用反射破坏单例模式");
}
}
private static final Single01 SingleTon = new Single01();
public static Single01 getInstance(){
return SingleTon;
}
//预防反序列化破坏单例模式
public Object readResolve(){
return SingleTon;
}
}
2:枚举类实现饿汉式单例模式
/*
* 枚举类实现单例模式
* 饿汉式的,类一加载就已经创建了单例对象
*
* 这时候不会被反序列化破坏
*
* 枚举类没有无参构造,也不能用反射破坏
*
* 但是Unsafe还是能够破坏单例模式
*/
enum Sex implements Serializable{
MALE;//枚举的这个就是唯一的一个单例,就是这个枚举类的单例,默认是public的
public static void method(){
System.out.println("实现单例模式");
}
}
3:DCL懒汉式
/*
*DCL懒汉式实现单例模式
*/
class Lazy{
//这个时候必须要加volatile
//保证可见性,不保证原子性,禁止指令重排序
/*
* 为什么这里一定要加volatile一定要加呢?
*
* 在单线程下指令重排序是不会影响的,但是多线程下就可能会出现问题
* */
private volatile static Lazy lazy=null;
private Lazy() {
if (lazy!=null){
throw new RuntimeException("请不要试图用反射破坏单例模式");
}
}
public static Lazy getInstance(){
if (lazy==null){
//首次调用的时候才进行同步,以免影响性能,只有在第一次创建的时候才会存在同步竞争,影响性能,创建好了之后
//就不会存在同步代码块的调用了,也就没有了性能的损失
synchronized (Lazy.class){
//双检锁避免一个同步代码块刚进入,就执行完了。而另一个线程在同步代码块之前进入了第一个if判断,这时候就会创建多个对象。
if (lazy==null){
lazy = new Lazy();
}
}
}
return lazy;
}
}
4:内部类懒汉式单例模式
/*
* 内部类的方式
* 实现懒汉式单例模式
*/
class staticInner{
private staticInner() {
}
private static class innerClass{
//静态变量在类加载的时候就初始化了,jvm保证多线程下的安全
static staticInner inner = new staticInner();
}
public static staticInner getInstance(){
return innerClass.inner;
}
}
总结一下上面四种方式:
1:饿汉式
2:枚举类饿汉式
3:双检锁懒汉式
4:静态内部类懒汉式
单例模式在jdk中的体现
public static void main(String[] args) throws Exception {
System.exit(0);
System.gc();
/*
*上面两个方法的底层都是调用了Runtime.getRuntime()的方法
*/
}
那我们看一下这个类的源码,可以发现这就是饿汉式的单例模式在jdk中的体现
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
Collections类中还有大量的单例模式的实现。有很多私有的静态内部类。里面也有枚举实现的单例模式。