主要思路:将构造方法私有化,并对外提供一个static的方法来创建对象
public class Hungry {
?
? ?private Hungry(){
?
? }
? ?private final static Hungry hungry = new Hungry();
? ?public static Hungry getInstance(){
? ? ? ?return hungry;
? }
?
? ?public static void main(String[] args) {
? ? ? ?Hungry hungry1 = Hungry.getInstance();
? ? ? ?Hungry hungry2 = hungry.getInstance();
? ? ? ?System.out.println(hungry1==hungry2);//true
? }
}
缺点:一开始就创建对象,占用系统资源
public class Lazy {
?
? ?private Lazy(){
? ? ? ?System.out.println(Thread.currentThread().getName()+"ok");
? }
?
? ?private static Lazy lazy;
?
? ?public static Lazy getInstance(){
? ? ? ?if(lazy==null){
? ? ? ? ? ?lazy = new Lazy();
? ? ? }
? ? ? ?return lazy;
? }
?
? ?public static void main(String[] args) {
? ? ? for(int i=0;i<10;i++){
? ? ? ? ? new Thread(()->{
? ? ? ? ? ? ? Lazy.getInstance();
? ? ? ? ? }).start();
? ? ? }
? }
}
?
单线程下不会出现问题,但多线程会会有并发问题,main方法的测试结果:
Thread-0ok
Thread-2ok
Thread-3ok
会发生同一时间创建了多个对象,所以出现了DCL双重检索
public class Lazy {
?
? ?private Lazy(){
? ? ? ?System.out.println(Thread.currentThread().getName()+"ok");
? }
?
? ?private volatile static Lazy lazy; //volatile保证不会出现代码重排
?
? ?public static Lazy getInstance(){
? ? ? ?if(lazy==null) {
? ? ? ? ? ?synchronized (Lazy.class) {
? ? ? ? ? ? ? ?if (lazy == null) {
? ? ? ? ? ? ? ? ? ?lazy = new Lazy();
? ? ? ? ? ? ? ? ? ?/*
? ? ? ? ? ? ? ? ? ? ? ?这个过程不是一个原子性,会出现代码重排现象
? ? ? ? ? ? ? ? ? ? ? ?1.开配空间
? ? ? ? ? ? ? ? ? ? ? ?2.执行构造方法
? ? ? ? ? ? ? ? ? ? ? ?3.引用执行
? ? ? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? }
? ? ? ? ? }
? ? ? }
? ? ? ?return lazy;
? }
?
? ?public static void main(String[] args) {
? ? ? for(int i=0;i<10;i++){
? ? ? ? ? new Thread(()->{
? ? ? ? ? ? ? Lazy.getInstance();
? ? ? ? ? }).start();
? ? ? }
? }
}
可以实现延迟实例化,并且是线程安全的
public class Holder {
? ?private Holder(){
? ? ? ?System.out.println(Thread.currentThread().getName()+"ok");
? }
?
? ?public static Holder getInstance(){
? ? ? ?return InnerClass.holder;
? }
?
? ?public static class InnerClass{
? ? ? ?private static final Holder holder = new Holder();
? }
?
? ?public static void main(String[] args) {
? ? ? ?for (int i = 0; i < 10; i++) {
? ? ? ? ? ?new Thread(()->{
? ? ? ? ? ? ? ?Holder.getInstance();
? ? ? ? ? }).start();
? ? ? }
? }
}
可以采用额外的变量进行控制,防止反射
public class Lazy {
?
? ?private Lazy(){
? ? ? ?synchronized (Lazy.class){
? ? ? ? ? ?if(temp == false){
? ? ? ? ? ? ? ?temp = true;
? ? ? ? ? }else{
? ? ? ? ? ? ? ?throw new RuntimeException("不要用反射破坏单例");
? ? ? ? ? }
? ? ? }
? }
?
? ?private volatile static Lazy lazy; //volatile保证不会出现代码重排
?
? ?public static Lazy getInstance(){
? ? ? ?if(lazy==null) {
? ? ? ? ? ?synchronized (Lazy.class) {
? ? ? ? ? ? ? ?if (lazy == null) {
? ? ? ? ? ? ? ? ? ?lazy = new Lazy();
? ? ? ? ? ? ? ? ? ?/*
? ? ? ? ? ? ? ? ? ? ? ?这个过程不是一个原子性,会出现代码重排现象
? ? ? ? ? ? ? ? ? ? ? ?1.开配空间
? ? ? ? ? ? ? ? ? ? ? ?2.执行构造方法
? ? ? ? ? ? ? ? ? ? ? ?3.引用指向
? ? ? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? }
? ? ? ? ? }
? ? ? }
? ? ? ?return lazy;
? }
?
? ?public static void main(String[] args) throws Exception {
? ? ? ?Lazy lazy = Lazy.getInstance();
? ? ? ?Constructor<Lazy> declaredConstructor = Lazy.class.getDeclaredConstructor(null);
? ? ? ?declaredConstructor.setAccessible(true);
? ? ? ?Lazy lazy1 = declaredConstructor.newInstance();
? ? ? ?System.out.println(lazy==lazy1);
? }
}
防止反射破坏
public enum EnumSingleton {
? ?INSTANCE;
? ?private EnumSingleton() {
?
? }
?
? ?public EnumSingleton getInstance(){
? ? ? ?return INSTANCE;
? }
?
? ?public static void main(String[] args) throws Exception {
? ? ? ?EnumSingleton instance = EnumSingleton.INSTANCE;
? ? ? ?Constructor<EnumSingleton> declaredConstructor = EnumSingleton.class.getDeclaredConstructor(String.class,int.class);
? ? ? ?declaredConstructor.setAccessible(true);
? ? ? ?EnumSingleton instance1 = declaredConstructor.newInstance();
? ? ? ?System.out.println(instance==instance1);
? }
}
重写readResolve()方法
private Object readResolve() throws ObjectStreamException{
? ? ? ?return singleton;
}