亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

Java之23種設計模式-單例模式

標簽:
Java 面試 架構

单例模式

       单例对象(Singleton)是一种常用的设计模式。在 Java 应用中,单例对象能保证在一个 JVM 中,该对象只有一个实例存在。这样的模式有几个好处:

1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。

2、省去了 new 操作符,降低了系统内存的使用频率,减轻 GC 压力。

3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全 乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式, 才能保证核心交易服务器独立控制整个流程。 

1)饿汉式

单例模式中的饿汉式是在类加载的时候就已经初始化了:如下:

Singleton.java

package com.lxj.singleton;

public class Singleton {
        
    /* 私有构造方法,防止被实例化 */
	 private Singleton() {
		 
	 }
	 
    /* 持有私有静态实例,防止被引用,此处赋值为 null,目的是实现延迟加载 */
	 private static  Singleton instance = new Singleton();
	 
	 
    /* 静态工程方法,创建实例 */
	 public static Singleton getInstance() {
		 return instance;
	 }
	
	 
	 public static void main(String[] args) {
		 Singleton instance1 = Singleton.getInstance();
		 Singleton instance2 = Singleton.getInstance();
		 System.out.println(instance1 == instance2);
	 }
}

运行结果:

true

getInstance()方法获取的实例对象的引用是相同的,说明他们都指向堆空间相同的引用。

2)懒汉式

Singleton.java

package com.lxj.singleton;

//懒汉式:在需要获取对象时才new对象,堆空间分配内存
//存在线程安全问题
public class Singleton {
    
     /* 私有构造方法,防止被实例化 */
	 private Singleton() {}
	 
     /* 持有私有静态实例,防止被引用,此处赋值为 null,目的是实现延迟加载 */
	 private static  Singleton instance = null;
	 
	/* 静态工程方法,创建实例 */ 
    public static Singleton getInstance() {
		 
		 if(instance == null) {
			 instance = new Singleton(); 
		 }
		 return instance;
	 }
	 
	 public static void main(String[] args) {
		 Singleton instance1 = Singleton.getInstance();
		 Singleton instance2 = Singleton.getInstance();
		 System.out.println(instance1 == instance2);
	 }
}

运行结果:

true

从上面的结果看,的确是单例模式,但是在多线程的环境下可能因为在刚刚要执行new Singleton()对象时,CPU切换到另外的线程,导致后面的线程同样进入if(instanfce == null) 的语句。导致创建了不同的对象。所以我们应该考虑使用同步。

package com.lxj.singleton;

//懒汉式:在需要获取对象时才new对象,堆空间分配内存
//存在线程安全问题
public class Singleton implements Runnable{
    
	 private Singleton() {}
	 
	 private static  Singleton instance = null;
	 
	 public static  Singleton getInstance() {
		 
		 if(instance == null) {
			try {   //这里停顿是为了放大出现线程安全
				Thread.sleep(400);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			 instance = new Singleton(); 
		 }
		 return instance;
	 }

	@Override
	public void run() {
		for(int i = 0 ; i < 10 ; i++) {
			Singleton instance2 = Singleton.getInstance();
			System.out.println(Thread.currentThread().getName()+instance2);
		}
	}
	
	public static void main(String[] args) {
		
		Singleton singleton = new Singleton();
		Thread thread = new Thread(singleton);
		Thread.currentThread().setName("主线程: ");
		thread.setName("副线程: ");
		thread.start();
		for(int i = 0 ; i < 10 ; i++) {
			Singleton instance2 = Singleton.getInstance();
			System.out.println(Thread.currentThread().getName()+instance2);
		}
	}
}

运行结果:

副线程: com.lxj.singleton.Singleton@24bd02ff
副线程: com.lxj.singleton.Singleton@24bd02ff
副线程: com.lxj.singleton.Singleton@24bd02ff
副线程: com.lxj.singleton.Singleton@24bd02ff
副线程: com.lxj.singleton.Singleton@24bd02ff
副线程: com.lxj.singleton.Singleton@24bd02ff
主线程: com.lxj.singleton.Singleton@7852e922 //这里的hashCode的十六进制码不同,说明出现问题了
主线程: com.lxj.singleton.Singleton@24bd02ff
主线程: com.lxj.singleton.Singleton@24bd02ff
主线程: com.lxj.singleton.Singleton@24bd02ff
主线程: com.lxj.singleton.Singleton@24bd02ff
主线程: com.lxj.singleton.Singleton@24bd02ff
主线程: com.lxj.singleton.Singleton@24bd02ff
副线程: com.lxj.singleton.Singleton@24bd02ff
主线程: com.lxj.singleton.Singleton@24bd02ff
副线程: com.lxj.singleton.Singleton@24bd02ff
主线程: com.lxj.singleton.Singleton@24bd02ff
副线程: com.lxj.singleton.Singleton@24bd02ff
副线程: com.lxj.singleton.Singleton@24bd02ff
主线程: com.lxj.singleton.Singleton@24bd02ff

现在考虑加synchronized关键字

	 
	 public static synchronized Singleton getInstance() {
		 
		 if(instance == null) {
			 try {
				Thread.sleep(400);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			 instance = new Singleton(); 
		 }
		 return instance;
	 }

运行结果:

副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922

但是,synchronized 关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为 每次调用 getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加 锁,之后就不需要了,所以,这个地方需要改进。我们改成下面这个:

	public static Singleton getInstance() {

		if (instance == null) {
            //如果后面的线程发现为空才进到这里,实例化后,就不会往下执行了
			synchronized (Singleton.class) {
				if (instance == null) {
					try {
						Thread.sleep(400);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					instance = new Singleton();
				}
			}
		}
		return instance;
	}

运行结果:
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
主线程: com.lxj.singleton.Singleton@7852e922
副线程: com.lxj.singleton.Singleton@7852e922

这就是单例模式的懒汉式和恶汉式常用的创建方式,关于单例模式还有很多复杂的用法跟可能出现的问题,需要慢慢去摸索,最后推荐一个jdk中用到的单例模式,java.lang包下的Runtime类,一个单例模式的使用。




點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
JAVA開發工程師
手記
粉絲
7794
獲贊與收藏
665

關注作者,訂閱最新文章

閱讀免費教程

  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消