1. 程式人生 > >Java單例模式及開發應用場景

Java單例模式及開發應用場景

       所謂單例,指的就是單例項,有且僅有一個類例項,這個單例不應該由人來控制,而應該由程式碼來限制,強制單例。

  單例有其獨有的使用場景,一般是對於那些業務邏輯上限定不能多例只能單例的情況,例如:類似於計數器之類的存在,一般都需要使用一個例項來進行記錄,若多例計數則會不準確。

  其實單例就是那些很明顯的使用場合,沒有之前學習的那些模式所使用的複雜場景,只要你需要使用單例,那你就使用單例,簡單易理解。

1、常見的單例模式有兩種建立方式:所謂餓懶漢式與餓漢式

(1)懶漢式

  何為懶?顧名思義,就是不做事,這裡也是同義,懶漢式就是不在系統載入時就建立類的單例,而是在第一次使用例項的時候再建立。

詳見下方程式碼示例:

 1 public class LHanDanli {
 2     //定義一個私有類變數來存放單例,私有的目的是指外部無法直接獲取這個變數,而要使用提供的公共方法來獲取
 3     private static LHanDanli dl = null;
 4     //定義私有構造器,表示只在類內部使用,亦指單例的例項只能在單例類內部建立
 5     private LHanDanli(){}
 6     //定義一個公共的公開的方法來返回該類的例項,由於是懶漢式,需要在第一次使用時生成例項,所以為了執行緒安全,使用synchronized關鍵字來確保只會生成單例
 7     public static
synchronized LHanDanli getInstance(){ 8 if(dl == null){ 9 dl = new LHanDanli(); 10 } 11 return dl; 12 } 13 }

(2)餓漢式

  又何為餓?餓者,飢不擇食;但凡有食,必急食之。此處同義:在載入類的時候就會建立類的單例,並儲存在類中。

詳見下方程式碼示例:

 1 public class EHanDanli {
 2     //此處定義類變數例項並直接例項化,在類載入的時候就完成了例項化並儲存在類中
 3     private
static EHanDanli dl = new EHanDanli(); 4 //定義無參構造器,用於單例例項 5 private EHanDanli(){} 6 //定義公開方法,返回已建立的單例 7 public static EHanDanli getInstance(){ 8 return dl; 9 } 10 }

2、雙重加鎖機制

  何為雙重加鎖機制?

  在懶漢式實現單例模式的程式碼中,有使用synchronized關鍵字來同步獲取例項,保證單例的唯一性,但是上面的程式碼在每一次執行時都要進行同步和判斷,無疑會拖慢速度,使用雙重加鎖機制正好可以解決這個問題:

 1 public class SLHanDanli {
 2     private static volatile SLHanDanli dl = null;
 3     private SLHanDanli(){}
 4     public static SLHanDanli getInstance(){
 5         if(dl == null){
 6             synchronized (SLHanDanli.class) {
 7                 if(dl == null){
 8                     dl = new SLHanDanli();
 9                 }
10             }
11         }
12         return dl;
13     }
14 }

  看了上面的程式碼,有沒有感覺很無語,雙重加鎖難道不是需要兩個synchronized進行加鎖的嗎?

  ......

  其實不然,這裡的雙重指的的雙重判斷,而加鎖單指那個synchronized,為什麼要進行雙重判斷,其實很簡單,第一重判斷,如果單例已經存在,那麼就不再需要進行同步操作,而是直接返回這個例項,如果沒有建立,才會進入同步塊,同步塊的目的與之前相同,目的是為了防止有兩個呼叫同時進行時,導致生成多個例項,有了同步塊,每次只能有一個執行緒呼叫能訪問同步塊內容,當第一個搶到鎖的呼叫獲取了例項之後,這個例項就會被建立,之後的所有呼叫都不會進入同步塊,直接在第一重判斷就返回了單例。至於第二個判斷,個人感覺有點查遺補漏的意味在內(期待高人高見)。

  不論如何,使用了雙重加鎖機制後,程式的執行速度有了顯著提升,不必每次都同步加鎖。

  其實我最在意的是volatile的使用,volatile關鍵字的含義是:被其所修飾的變數的值不會被本地執行緒快取,所有對該變數的讀寫都是直接操作共享記憶體來實現,從而確保多個執行緒能正確的處理該變數。該關鍵字可能會遮蔽掉虛擬機器中的一些程式碼優化,所以其執行效率可能不是很高,所以,一般情況下,並不建議使用雙重加鎖機制,酌情使用才是正理!

3、類級內部類方式

  餓漢式會佔用較多的空間,因為其在類載入時就會完成例項化,而懶漢式又存在執行速率慢的情況,雙重加鎖機制呢?又有執行效率差的毛病,有沒有一種完美的方式可以規避這些毛病呢?

  貌似有的,就是使用類級內部類結合多執行緒默認同步鎖,同時實現延遲載入和執行緒安全。

1 public class ClassInnerClassDanli {
2     public static class DanliHolder{
3         private static ClassInnerClassDanli dl = new ClassInnerClassDanli();
4     }
5     private ClassInnerClassDanli(){}
6     public static ClassInnerClassDanli getInstance(){
7         return DanliHolder.dl;
8     }
9 }

  如上程式碼,所謂類級內部類,就是靜態內部類,這種內部類與其外部類之間並沒有從屬關係,載入外部類的時候,並不會同時載入其靜態內部類,只有在發生呼叫的時候才會進行載入,載入的時候就會建立單例例項並返回,有效實現了懶載入(延遲載入),至於同步問題,我們採用和餓漢式同樣的靜態初始化器的方式,藉助JVM來實現執行緒安全。

  其實使用靜態初始化器的方式會在類載入時建立類的例項,但是我們將例項的建立顯式放置在靜態內部類中,它會導致在外部類載入時不進行例項建立,這樣就能實現我們的雙重目的:延遲載入和執行緒安全。


一、單例模式:在spring中其實是scope(作用範圍)引數的預設設定值每個bean定義只生成一個物件例項,每次getBean請求獲得的都是此例項
單例模式分為餓漢模式和懶漢模式,
餓漢模式
spring singleton的預設是餓漢模式:啟動容器時(即例項化容器時),為所有spring配置檔案中定義的bean都生成一個例項
懶漢模式
在第一個請求時才生成一個例項,以後的請求都呼叫這個例項
spring singleton設定為懶漢模式:
<beans
default-lazy-init="true">
二、另一種和singleton對應的scope值---prototype多例項模式呼叫getBean時,就new一個新例項
singleton和prototype的比較

singleton:

xml配置檔案:
<bean id="dvdTypeDAO" class="com.terana.hibernate.impl.DvdTypeDAOImpl" />   
測試程式碼:
        ctx = new ClassPathXmlApplicationContext("spring-hibernate-mysql.xml");
        DvdTypeDAO tDao1 = (DvdTypeDAO)ctx.getBean("dvdTypeDAO");
        DvdTypeDAO tDao2 = (DvdTypeDAO)ctx.getBean("dvdTypeDAO");
執行:        
true
[email protected]
[email protected]

說明前後兩次getBean()獲得的是同一例項,說明spring預設是單例

prototype:
<bean id="dvdTypeDAO" class="com.terana.hibernate.impl.DvdTypeDAOImpl" scope="prototype" />
執行同樣的測試程式碼
執行:
false
[email protected]
[email protected]
說明scope="prototype"後,每次getBean()的都是不同的新例項

相關推薦

Java模式開發應用場景

       所謂單例,指的就是單例項,有且僅有一個類例項,這個單例不應該由人來控制,而應該由程式碼來限制,強制單例。  單例有其獨有的使用場景,一般是對於那些業務邏輯上限定不能多例只能單例的情況,例如:類似於計數器之類的存在,一般都需要使用一個例項來進行記錄,若多例計數則會

設計模式模式>>應用場景實現

arr unit 應用 lose sys time 初始 sin turn 定義 單例模式(Singleton),也叫單子模式,是一種常用的軟件設計模式。對於系統而言該實例有且僅有一個。 應用場景 線程池、數據庫池、用於對系統做初始化的實例,提供給關聯系統調用的接口(

建立型:模式相關應用

文章目錄 單例模式(Singleton) 優缺點 重點 懶漢式實現 執行緒不安全 synchronized關鍵字 雙重校驗鎖 靜態內部類 餓漢式實現 單例模式

Java模式建立模式的多執行緒問題 volatile synchronized 關鍵字

接下來,說說我對多執行緒中volitile 和 synchronized的理解 這兩個關鍵字都是java內建的用於實現執行緒同步的機制,其中: volitile用於修飾變數,用於同步主記憶體和執行緒儲存中的變數值,但是volitile使用應牢記 —— 只有在狀態真正獨立

java 模式在SSH框架中運用

定義: 確保某一個類只有一個例項,而且自動例項化並向整個系統提供這個例項。 程式碼: Singleton類稱為單例類,通過使用private的建構函式確保了在一個應用中只產生一個例項,並且是自行例項化的。 Java程式碼   /**   * 執行緒安全的

設計模式 | 模式典型應用

單例是最常見的設計模式之一,實現的方式非常多,同時需要注意的問題也非常多。 本文主要內容: 介紹單例模式 介紹單例模式的N中寫法 單例模式的安全性 序列化攻擊 反射攻擊 單例模式總結 介紹單例模式的典型應用

Java模式延遲載入

單例模式是 軟體開發中非常重要的模式之一。絕大多數的軟體專案中都會用到單例模式。單例模式應用的好與壞在高併發訪問的情況下效能差異較為明顯。下面我們來看一下單例模式的具體解釋。 描述:單例模式許多時候是

java模式雙重檢驗鎖的優缺點?還有哪些實現方式?列舉一些使用場景

2018年7月18日,在專案程式碼中看到單例模式,總結一下單例模式的知識點. 單例模式的概念: 在應用程式的生命週期中,在任意時刻,引用某個類的例項都是同一個.在一個系統中有些類只需要有一個全域性物件,統一管理系統行為和執行某些操作.例如在使用hibernate時,ses

一個JAVA模式的典型錯誤應用的分析和解決方法

                問題來自論壇,其程式碼如下:[java] view plain copy print?import java.sql.Connection;  import java.sql.PreparedStatement;  import java.sql.ResultSet;  imp

Java模式之懶漢模式餓漢模式

單例模式 單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。 這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。這個類提供了一種訪問其唯一

JAVA中的餓漢式和飽漢式模式jdk中Runtime類的模式實現方式詳解

一、描述 單例模式是一種非常常見的設計模式,即一個類只能有一個物件(例項),一般通過將該類的構造器私有化,來阻止在該類外建立該類的物件,並提供給外界一個唯一的物件(這個物件在該類中建立)。        java中的單例模式常見的有兩種實現方式,一種是惡漢方式,即將該類物件

Java設計模式模式在Android中的重要使用

  之前在開發中老用到一些設計模式可是呢又不是很懂,於是狠下心來琢磨一番。下面是我琢磨後總結的,希望對您有用。如果發現了問題,請幫忙指正。 一、單例模式是什麼?   單例模式最初的定義出現於《設計模式》:“保證一個類僅有一個例項,並提供一個訪問它的全域性

Java模式

class auth pre light java on() ack private gets package singleton; /** * 單例模式 * @author pengYi * */ public class Singleton { priva

java模式等一些程序的寫法....持續更新...

new tor zed bsp 更新 餓漢式 blog stat cto 一、單例模式的寫法: public class MyFactory { /** * 餓漢式 */ private static MyFactory instanc

老男孩教育每日一題-第83天-binlog是什麽?記錄的什麽?有幾種工作模式企業應用場景

mysql binlog 每日一題 參考答案含義binlog:是用於記錄所有更新了數據的操作語句,語句以事件的形式保存,它描述數據的更改過程作用:用於實時備份數據,數據庫的主從復制log_bin 打開記錄binlog功能binlog的查看mysqlbinlog /home/mysql/binlog

模式常見寫法分析(設計模式01)

啟動 nes 成員變量 額外 log 序列 spa tar adl 保證一個類僅有一個實例。並提供一個該實例的全局訪問點。 ——《設計模式》單例模式的概念非常easy。以下以C#語言為樣例,列出常見單例寫法的優缺點。1、簡單實現 public s

java 模式

多線程安全 except detail 追加 earch 繼承 好處 config 什麽是 單例模式(Singleton)也叫單態模式,是設計模式中最為簡單的一種模式,甚至有些模式大師都不稱其為模式,稱其為一種實現技巧,因為設計模式講究對象之間的關系的抽象,而單例模式只有自

c++的模式c++11對模式的優化

on() end per let namespace lease 是否 存在 建立 單例模式 單例模式,可以說設計模式中最常應用的一種模式了,據說也是面試官最喜歡的題目。但是如果沒有學過設計模式的人,可能不會想到要去應用單例模式,面對單例模式適用的情況,可能會優先考慮使用全

java模式的心得

開發人員 性能 文章 人員 外部 訪問 單例 鎖定 初始化   由於設計模式對於java高級開發人員來說是非常重要的,網上也有很多關於設計模式的文章,博客等。所以,首先我對相對簡單的單例模式做一個簡單的總結。   一、實現方式   單例模式的實現方式有3種,分別是餓漢式

Java模式深入詳解

protected test 異常 except while 深入 bject his 不一致 Java單例模式深入詳解 一.問題引入   偶然想想到的如果把Java的構造方法弄成private,那裏面的成員屬性是不是只有通過static來訪問呢;如果構造方法是privat