主要思路:將構(gòu)造方法私有化,并對外提供一個(gè)static的方法來創(chuàng)建對象
餓漢式單例
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
? }
}
缺點(diǎn):一開始就創(chuàng)建對象,占用系統(tǒng)資源
懶漢式單例
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();
? ? ? }
? }
}
?
單線程下不會出現(xiàn)問題,但多線程會會有并發(fā)問題,main方法的測試結(jié)果:
Thread-0ok
Thread-2ok
Thread-3ok
會發(fā)生同一時(shí)間創(chuàng)建了多個(gè)對象,所以出現(xiàn)了DCL雙重檢索
DCL懶漢式
public class Lazy {
?
? ?private Lazy(){
? ? ? ?System.out.println(Thread.currentThread().getName()+"ok");
? }
?
? ?private volatile static Lazy lazy; //volatile保證不會出現(xiàn)代碼重排
?
? ?public static Lazy getInstance(){
? ? ? ?if(lazy==null) {
? ? ? ? ? ?synchronized (Lazy.class) {
? ? ? ? ? ? ? ?if (lazy == null) {
? ? ? ? ? ? ? ? ? ?lazy = new Lazy();
? ? ? ? ? ? ? ? ? ?/*
? ? ? ? ? ? ? ? ? ? ? ?這個(gè)過程不是一個(gè)原子性,會出現(xiàn)代碼重排現(xiàn)象
? ? ? ? ? ? ? ? ? ? ? ?1.開配空間
? ? ? ? ? ? ? ? ? ? ? ?2.執(zhí)行構(gòu)造方法
? ? ? ? ? ? ? ? ? ? ? ?3.引用執(zhí)行
? ? ? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? }
? ? ? ? ? }
? ? ? }
? ? ? ?return lazy;
? }
?
? ?public static void main(String[] args) {
? ? ? for(int i=0;i<10;i++){
? ? ? ? ? new Thread(()->{
? ? ? ? ? ? ? Lazy.getInstance();
? ? ? ? ? }).start();
? ? ? }
? }
}
可以實(shí)現(xiàn)延遲實(shí)例化,并且是線程安全的
靜態(tài)內(nèi)部類
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();
? ? ? }
? }
}
反射破解單例模式
可以采用額外的變量進(jìn)行控制,防止反射
public class Lazy {
?
? ?private Lazy(){
? ? ? ?synchronized (Lazy.class){
? ? ? ? ? ?if(temp == false){
? ? ? ? ? ? ? ?temp = true;
? ? ? ? ? }else{
? ? ? ? ? ? ? ?throw new RuntimeException("不要用反射破壞單例");
? ? ? ? ? }
? ? ? }
? }
?
? ?private volatile static Lazy lazy; //volatile保證不會出現(xiàn)代碼重排
?
? ?public static Lazy getInstance(){
? ? ? ?if(lazy==null) {
? ? ? ? ? ?synchronized (Lazy.class) {
? ? ? ? ? ? ? ?if (lazy == null) {
? ? ? ? ? ? ? ? ? ?lazy = new Lazy();
? ? ? ? ? ? ? ? ? ?/*
? ? ? ? ? ? ? ? ? ? ? ?這個(gè)過程不是一個(gè)原子性,會出現(xiàn)代碼重排現(xiàn)象
? ? ? ? ? ? ? ? ? ? ? ?1.開配空間
? ? ? ? ? ? ? ? ? ? ? ?2.執(zhí)行構(gòu)造方法
? ? ? ? ? ? ? ? ? ? ? ?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);
? }
}
枚舉單例
防止反射破壞文章來源:http://www.zghlxwxcb.cn/news/detail-817244.html
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()方法文章來源地址http://www.zghlxwxcb.cn/news/detail-817244.html
private Object readResolve() throws ObjectStreamException{
? ? ? ?return singleton;
}
到了這里,關(guān)于設(shè)計(jì)模式一(單例模式)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!