Java 實(shí)例解析單例模式
單例模式的介紹
單例對象(Singleton)是一種常用的設(shè)計模式。在實(shí)際使用中,單例對象能保證在一個JVM中,該對象只存在一個實(shí)例存在。
優(yōu)點(diǎn)
1、減少系統(tǒng)開銷,提高系統(tǒng)性能
2、省去了new操作符,降低了系統(tǒng)內(nèi)存的使用頻率,減輕GC壓力
3、避免對共享資源的多重占用
缺點(diǎn)
1、不適應(yīng)用多變的對象
2、擴(kuò)展困難
3、單例類的職責(zé)過重,在一定程度上違背了“單一職責(zé)原則”。
Synchronized
Synchronized示例
介紹單例模式前,我們現(xiàn)介紹一下Synchronized
示例如下:
建立一個內(nèi)部類,并開啟子線程,如果實(shí)例該類,則自動執(zhí)行test1()方法
class SynchronizedTest implements Runnable {
private int count;
public SynchronizedTest() {
count = 0;
}
@Override
public void run() {
test1();
}
private void test1() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + count++);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
構(gòu)造一個SynchronizedTest 對象,傳入兩個線程對象
SynchronizedTest test = new SynchronizedTest();
Thread thread1 = new Thread(test,"test1");
Thread thread2 = new Thread(test,"test2");
thread1.start();
thread2.start();
由結(jié)果可知,當(dāng)一個對象持有該代碼塊時,另一個線程訪問不到被鎖住的代碼塊,只要當(dāng)前一線程執(zhí)行完成,另一線程才能執(zhí)行。
test1:0
test1:1
test1:2
test1:3
test1:4
test2:5
test2:6
test2:7
test2:8
test2:9
Synchronized與非Synchronized
建立一個內(nèi)部類
class SynchronizedTest implements Runnable {
private int count;
public SynchronizedTest() {
count = 0;
}
@Override
public void run() {
if (Thread.currentThread().getName().equals("S")) {
test1();
} else {
test2();
}
}
public void test1() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void test2() {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + count);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
SynchronizedTest test = new SynchronizedTest();
Thread thread1 = new Thread(test,"S");
Thread thread2 = new Thread(test,"N");
thread1.start();
thread2.start();
由結(jié)果可知,一個線程訪問Synchronized修飾的代碼塊,另一個線程訪問非Synchronized代碼塊不受阻塞
S:0
N:1
N:2
S:1
N:2
S:2
S:3
N:4
S:4
N:5
Singleton
第一個示例
此示例實(shí)現(xiàn)了單例,但是如果放在多線程當(dāng)中,將會漏洞百出
我們接著看下一個改良示例
public class Singleton {
/* 持有私有靜態(tài)實(shí)例,防止被引用,此處賦值為null,目的是實(shí)現(xiàn)延遲加載 */
private static Singleton instance = null;
/* 私有構(gòu)造方法,防止被實(shí)例化 */
private Singleton() {
}
/* 靜態(tài)工程方法,創(chuàng)建實(shí)例 */
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
第二個示例
根據(jù)第一個示例,我們進(jìn)行改良,加上Synchronized。
但是每次調(diào)用getInstance()方法時,都會對對象上鎖,為了減少系統(tǒng)開銷,我們一般在第一次創(chuàng)建對象的時候加鎖,后面就不需要了
我們接著看下一個改良示例
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
第三個示例
我們對上一個示例進(jìn)行改良,只有在instance == null的時候,也就是第一次創(chuàng)建對象的時候,執(zhí)行加鎖的區(qū)域。此種寫法解決了上一個示例遺留的問題,但是在Java指令中創(chuàng)建對象和賦值操作是分開進(jìn)行的,也就是說instance = new Singleton();語句是分兩步執(zhí)行的。但是JVM并不保證這兩個操作的先后順序,也就是說有可能JVM會為新的Singleton實(shí)例分配空間,然后直接賦值給instance成員,然后再去初始化這個Singleton實(shí)例。
public static Singleton getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
第四個示例
此代碼初看已經(jīng)沒有問題,如果在構(gòu)造方法中出現(xiàn)異常,那么實(shí)例將得不到創(chuàng)建
public class Singleton {
/* 私有構(gòu)造方法,防止被實(shí)例化 */
private Singleton() {
}
/* 此處使用一個內(nèi)部類來維護(hù)單例 */
private static class SingletonFactory {
private static Singleton instance = new Singleton();
}
/* 獲取實(shí)例 */
public static Singleton getInstance() {
return SingletonFactory.instance;
}
}
第五個示例
private static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
if (instance == null){
sync();
}
return instance;
}
private static synchronized void sync(){
if (instance == null){
instance = new Singleton();
System.out.println("success");
}
}
到此這篇關(guān)于Java 實(shí)例解析單例模式的文章就介紹到這了,更多相關(guān)Java 單例模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java設(shè)計模式編程中的責(zé)任鏈模式使用示例
這篇文章主要介紹了Java設(shè)計模式編程中的責(zé)任鏈模式使用示例,責(zé)任鏈模式可以避免很多請求的發(fā)送者和接收者之間的耦合關(guān)系,需要的朋友可以參考下2016-05-05
java環(huán)境變量的配置方法圖文詳解【win10環(huán)境為例】
這篇文章主要介紹了java環(huán)境變量的配置方法,結(jié)合圖文形式詳細(xì)分析了win10環(huán)境下java環(huán)境變量的配置方法與相關(guān)操作注意事項,需要的朋友可以參考下2020-04-04
解決idea update project 更新選項消失的問題
這篇文章主要介紹了解決idea update project 更新選項消失的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01
Java異常 Exception類及其子類(實(shí)例講解)
下面小編就為大家?guī)硪黄狫ava異常 Exception類及其子類(實(shí)例講解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
Netty客戶端接入流程N(yùn)ioSocketChannel創(chuàng)建解析
這篇文章主要為大家介紹了Netty客戶端接入流程N(yùn)ioSocketChannel創(chuàng)建源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
簡易版SpringBoot自定義模擬實(shí)現(xiàn)
SpringBoot作為目前最流行的框架之一,極大地提高了開發(fā)效率和降低了學(xué)習(xí)成本,使得開發(fā)人員能夠更專注于業(yè)務(wù)邏輯的實(shí)現(xiàn),而無需過多關(guān)注底層框架的配置和集成,本文模擬實(shí)現(xiàn)簡易版SpringBoot2024-01-01
springboot集成gzip和zip數(shù)據(jù)壓縮傳輸(適用大數(shù)據(jù)信息傳輸)
?在大數(shù)據(jù)量的傳輸中,壓縮數(shù)據(jù)后進(jìn)行傳輸可以一定程度的解決速度問題,本文主要介紹了springboot集成gzip和zip數(shù)據(jù)壓縮傳輸,具有一定的參考價值,感興趣的可以了解一下2023-09-09
Spring配置中transactionAttributes的使用方法介紹
這篇文章主要介紹了Spring配置中transactionAttributes的使用方法介紹的相關(guān)內(nèi)容,具有一定參考價值,需要的朋友可以了解下。2017-09-09

