最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java單利模式與多線程總結(jié)歸納

 更新時(shí)間:2016年03月18日 10:00:52   作者:寶寶快來(lái)  
這篇文章主要介紹了Java單利模式與多線程總結(jié)歸納 的相關(guān)資料,需要的朋友可以參考下

概念:

  java中單例模式是一種常見(jiàn)的設(shè)計(jì)模式,單例模式分三種:懶漢式單例、餓漢式單例、登記式單例三種。

  單例模式有一下特點(diǎn):

  1、單例類(lèi)只能有一個(gè)實(shí)例。

  2、單例類(lèi)必須自己創(chuàng)建自己的唯一實(shí)例。

  3、單例類(lèi)必須給所有其他對(duì)象提供這一實(shí)例。

  單例模式確保某個(gè)類(lèi)只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。在計(jì)算機(jī)系統(tǒng)中,線程池、緩存、日志對(duì)象、對(duì)話框、打印機(jī)、顯卡的驅(qū)動(dòng)程序?qū)ο蟪1辉O(shè)計(jì)成單例。這些應(yīng)用都或多或少具有資源管理器的功能。每臺(tái)計(jì)算機(jī)可以有若干個(gè)打印機(jī),但只能有一個(gè)Printer Spooler,以避免兩個(gè)打印作業(yè)同時(shí)輸出到打印機(jī)中。每臺(tái)計(jì)算機(jī)可以有若干通信端口,系統(tǒng)應(yīng)當(dāng)集中管理這些通信端口,以避免一個(gè)通信端口同時(shí)被兩個(gè)請(qǐng)求同時(shí)調(diào)用。總之,選擇單例模式就是為了避免不一致?tīng)顟B(tài),避免政出多頭。

這里主要詳細(xì)介紹兩種:懶漢式和餓漢式

一、立即加載/餓漢式

在調(diào)用方法前,實(shí)例就已經(jīng)被創(chuàng)建,代碼:

package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
// 立即加載方式==惡漢模式
private static MyObject myObject = new MyObject();
private MyObject() {
}
public static MyObject getInstance() {
// 此代碼版本為立即加載
// 此版本代碼的缺點(diǎn)是不能有其他實(shí)例變量
// 因?yàn)間etInstance()方法沒(méi)有同步
// 所以有可能出現(xiàn)非線程安全的問(wèn)題
return myObject;
}
}

創(chuàng)建線程類(lèi)

package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}

創(chuàng)建運(yùn)行類(lèi)

package com.weishiyao.learn.day.singleton.ep;
public class Run {
public static void main(String[] args) {
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
t.start();
t.start();
t.start();
}
}

運(yùn)行結(jié)果

1 167772895
2 167772895
3 167772895

hashCode是同一個(gè)值,說(shuō)明對(duì)象也是同一個(gè),說(shuō)明實(shí)現(xiàn)了立即加載型的單利模式

二、延遲加載/懶漢式

在調(diào)用方法以后實(shí)例才會(huì)被創(chuàng)建,實(shí)現(xiàn)方案可以是將實(shí)例化放到無(wú)參構(gòu)造函數(shù)當(dāng)中,這樣只有當(dāng)調(diào)用的時(shí)候才會(huì)創(chuàng)建對(duì)象的實(shí)例,代碼:

package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
private static MyObject myObject;
private MyObject() {
}
public static MyObject getInstance() {
// 延遲加載
if (myObject != null) {
} else {
myObject = new MyObject();
}
return myObject;
}
}

創(chuàng)建線程類(lèi)

package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
} 

創(chuàng)建運(yùn)行類(lèi)

package com.weishiyao.learn.day8.singleton.ep2;
public class Run {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
}
} 

運(yùn)行結(jié)果

1 167772895

這樣雖然取出了一個(gè)對(duì)象的實(shí)例,但是如果在多線程的環(huán)境中,就會(huì)出現(xiàn)多個(gè)實(shí)例的情況,這樣就不是單例模式了

運(yùn)行測(cè)試類(lèi)

package com.weishiyao.learn.day.singleton.ep;
public class Run {
public static void main(String[] args) {
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
t.start();
t.start();
t.start();
t.start();
t.start();
}
}

運(yùn)行結(jié)果

1 980258163
2 1224717057
3 1851889404
4 188820504
5 1672864109

既然出現(xiàn)問(wèn)題,就要解決問(wèn)題,在懶漢模式中的多線程的解決方案,代碼:

第一種方案,最常見(jiàn)的,加synchronized,而synchronized可以加到不同的位置

第一種,方法鎖

package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
private static MyObject myObject;
private MyObject() {
}
synchronized public static MyObject getInstance() {
// 延遲加載
try {
if (myObject != null) {
} else {
// 模擬在創(chuàng)建對(duì)象之前做一些準(zhǔn)備性的工作
Thread.sleep(); myObject = new MyObject(); }
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
} 

這種synchronized的同步方案導(dǎo)致效率過(guò)于低下,整個(gè)方法都被鎖住

第二種synchronized使用方案

package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
private static MyObject myObject;
private MyObject() {
}
public static MyObject getInstance() {
// 延遲加載
try {
synchronized (MyObject.class) {
if (myObject != null) {
} else {
// 模擬在創(chuàng)建對(duì)象之前做一些準(zhǔn)備性的工作
Thread.sleep();
myObject = new MyObject();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

這種方法效率一樣很低,方法內(nèi)的所有代碼都被鎖住,只需要鎖住關(guān)鍵代碼就好,第三種synchronized使用方案

package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
private static MyObject myObject;
private MyObject() {
}
public static MyObject getInstance() {
// 延遲加載
try {
if (myObject != null) {
} else {
// 模擬在創(chuàng)建對(duì)象之前做一些準(zhǔn)備性的工作
Thread.sleep();
synchronized (MyObject.class) {
myObject = new MyObject();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
} 

這么寫(xiě)看似是最優(yōu)方案了,但是,運(yùn)行一下結(jié)果,發(fā)現(xiàn),其實(shí)它是非線程安全的

結(jié)果:

1 1224717057
2 971173439
3 1851889404
4 1224717057
5 1672864109
Why?

雖然鎖住了對(duì)象創(chuàng)建的語(yǔ)句,每次只能有一個(gè)線程完成創(chuàng)建,但是,當(dāng)?shù)谝粋€(gè)線程進(jìn)來(lái)創(chuàng)建完成Object對(duì)象以后,第二個(gè)線程進(jìn)來(lái)還是可以繼續(xù)創(chuàng)建的,因?yàn)槲覀兙o緊只鎖住了創(chuàng)建語(yǔ)句,這個(gè)問(wèn)題解決方案

package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
private static MyObject myObject;
private MyObject() {
}
public static MyObject getInstance() {
// 延遲加載
try {
if (myObject != null) {
} else {
// 模擬在創(chuàng)建對(duì)象之前做一些準(zhǔn)備性的工作
Thread.sleep();
synchronized (MyObject.class) {
if (myObject == null) {
myObject = new MyObject();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

只需要在鎖里面再添加一個(gè)判斷,就可以保證單例了,這個(gè)是DCL雙檢查機(jī)制

結(jié)果如下:

1 1224717057
2 1224717057
3 1224717057
4 1224717057
5 1224717057

三、使用內(nèi)置靜態(tài)類(lèi)實(shí)現(xiàn)單例

主要代碼

package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
// 內(nèi)部類(lèi)方式
private static class MyObjectHandler {
private static MyObject myObject = new MyObject();
}
public MyObject() {
}
public static MyObject getInstance() {
return MyObjectHandler.myObject;
}
}

線程類(lèi)代碼

package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}

運(yùn)行類(lèi)

package com.weishiyao.learn.day.singleton.ep;
public class Run {
public static void main(String[] args) {
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
t.start();
t.start();
t.start();
t.start();
t.start();
}
}

結(jié)果

1851889404
1851889404
1851889404
1851889404
1851889404

通過(guò)內(nèi)部靜態(tài)類(lèi),得到了線程安全的單例模式

四、序列化和反序列化單例模式

內(nèi)置靜態(tài)類(lèi)可以達(dá)到線程安全的問(wèn)題,但如果遇到序列化對(duì)象時(shí),使用默認(rèn)方式得到的結(jié)果還是多例的

MyObject代碼

package com.weishiyao.learn.day8.singleton.ep5;
import java.io.Serializable;
public class MyObject implements Serializable {
/**
* 
*/
private static final long serialVersionUID = 888L;
// 內(nèi)部類(lèi)方式
private static class MyObjectHandler {
private static MyObject myObject = new MyObject();
}
public MyObject() {
}
public static MyObject getInstance() {
return MyObjectHandler.myObject;
}
// protected MyObject readResolve() {
// System.out.println("調(diào)用了readResolve方法!");
// return MyObjectHandler.myObject;
// }
}

業(yè)務(wù)類(lèi)

package com.weishiyao.learn.day.singleton.ep;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SaveAndRead {
public static void main(String[] args) {
try {
MyObject myObject = MyObject.getInstance();
FileOutputStream fosRef = new FileOutputStream(new File("myObjectFile.txt"));
ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
oosRef.writeObject(myObject);
oosRef.close();
fosRef.close();
System.out.println(myObject.hashCode());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
FileInputStream fisRef;
try {
fisRef = new FileInputStream(new File("myObjectFile.txt"));
ObjectInputStream iosRef = new ObjectInputStream(fisRef);
MyObject myObject = (MyObject) iosRef.readObject();
iosRef.close();
fisRef.close();
System.out.println(myObject.hashCode());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} 

結(jié)果

1 970928725
2 1099149023

兩個(gè)不同的hashCode,證明并不是同一個(gè)對(duì)象,解決方案,添加下面這段代碼

  protected MyObject readResolve() {
System.out.println("調(diào)用了readResolve方法!");
return MyObjectHandler.myObject;
}

在反序列化的時(shí)候調(diào)用,可以得到同一個(gè)對(duì)象

System.out.println(myObject.readResolve().hashCode());

結(jié)果

1 1255301379
2 調(diào)用了readResolve方法!
3 1255301379

相同的hashCode,證明得到了同一個(gè)對(duì)象

五、使用static代碼塊實(shí)現(xiàn)單例

靜態(tài)代碼塊中的代碼在使用類(lèi)的時(shí)候就已經(jīng)執(zhí)行了,所以可以應(yīng)用靜態(tài)代碼快這個(gè)特性來(lái)實(shí)現(xiàn)單利模式

MyObject類(lèi)

package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
private static MyObject instance = null;
private MyObject() {
super();
}
static {
instance = new MyObject();
}
public static MyObject getInstance() {
return instance;
}
}

線程類(lèi)

package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
for (int i = ; i < ; i++) {
System.out.println(MyObject.getInstance().hashCode());
}
}
}

運(yùn)行類(lèi)

package com.weishiyao.learn.day.singleton.ep;
public class Run {
public static void main(String[] args) {
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
t.start();
t.start();
t.start();
t.start();
t.start();
}
}

運(yùn)行結(jié)果:

1 1678885403
2 1678885403
3 1678885403
4 1678885403
5 1678885403
6 1678885403
7 1678885403
8 1678885403
9 1678885403
10 1678885403
11 1678885403
12 1678885403
13 1678885403
14 1678885403
15 1678885403
16 1678885403
17 1678885403
18 1678885403
19 1678885403
20 1678885403
21 1678885403
22 1678885403
23 1678885403
24 1678885403
25 1678885403

通過(guò)靜態(tài)代碼塊只執(zhí)行一次的特性也成功的得到了線程安全的單例模式

六、使用enum枚舉數(shù)據(jù)類(lèi)型實(shí)現(xiàn)單例模式

枚舉enum和靜態(tài)代碼塊的特性類(lèi)似,在使用枚舉時(shí),構(gòu)造方法會(huì)被自動(dòng)調(diào)用,也可以用來(lái)實(shí)現(xiàn)單例模式

MyObject類(lèi)

package com.weishiyao.learn.day.singleton.ep;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public enum MyObject {
connectionFactory;
private Connection connection;
private MyObject() {
try {
System.out.println("調(diào)用了MyObject的構(gòu)造");
String url = "jdbc:mysql://...:/wechat_?useUnicode=true&characterEncoding=UTF-";
String name = "root";
String password = "";
String driverName = "com.mysql.jdbc.Driver";
Class.forName(driverName);
connection = DriverManager.getConnection(url, name, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
public Connection getConnection() {
return connection;
}
}

線程類(lèi)

package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
for (int i = ; i < ; i++) {
System.out.println(MyObject.connectionFactory.getConnection().hashCode());
}
}
}

運(yùn)行類(lèi)

package com.weishiyao.learn.day.singleton.ep;
public class Run {
public static void main(String[] args) {
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
MyThread t = new MyThread();
t.start();
t.start();
t.start();
t.start();
t.start();
}
}

運(yùn)行結(jié)果

1 調(diào)用了MyObject的構(gòu)造
2 56823666
3 56823666
4 56823666
5 56823666
6 56823666
7 56823666
8 56823666
9 56823666
10 56823666
11 56823666
12 56823666
13 56823666
14 56823666
15 56823666
16 56823666
17 56823666
18 56823666
19 56823666
20 56823666
21 56823666
22 56823666
23 56823666
24 56823666
25 56823666
26 56823666

上面這種寫(xiě)法將枚舉類(lèi)暴露了,違反了“職責(zé)單一原則”,可以使用一個(gè)類(lèi)將枚舉包裹起來(lái)

package com.weishiyao.learn.day.singleton.ep;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class MyObject {
public enum MyEnumSingleton {
connectionFactory;
private Connection connection;
private MyEnumSingleton() {
try {
System.out.println("調(diào)用了MyObject的構(gòu)造");
String url = "jdbc:mysql://...:/wechat_?useUnicode=true&characterEncoding=UTF-";
String name = "root";
String password = "";
String driverName = "com.mysql.jdbc.Driver";
Class.forName(driverName);
connection = DriverManager.getConnection(url, name, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
public Connection getConnection() {
return connection;
}
}
public static Connection getConnection() {
return MyEnumSingleton.connectionFactory.getConnection();
}
}

更改線程代碼

package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
for (int i = ; i < ; i++) {
System.out.println(MyObject.getConnection().hashCode());
}
}
} 

結(jié)果

1 調(diào)用了MyObject的構(gòu)造
2 1948356121
3 1948356121
4 1948356121
5 1948356121
6 1948356121
7 1948356121
8 1948356121
9 1948356121
10 1948356121
11 1948356121
12 1948356121
13 1948356121
14 1948356121
15 1948356121
16 1948356121
17 1948356121
18 1948356121
19 1948356121
20 1948356121
21 1948356121
22 1948356121
23 1948356121
24 1948356121
25 1948356121
26 1948356121

以上總結(jié)了單利模式與多線程結(jié)合時(shí)遇到的各種情況和解決方案,以供以后使用時(shí)查閱。

相關(guān)文章

  • Java使用poi-tl1.9.1生成Word文檔的技巧分享

    Java使用poi-tl1.9.1生成Word文檔的技巧分享

    本文將簡(jiǎn)單介紹poi-tl的相關(guān)知識(shí),通過(guò)一個(gè)實(shí)際的案例實(shí)踐,充分介紹如何利用poi-tl進(jìn)行目標(biāo)文檔的生成,同時(shí)分享幾個(gè)不同的office版本如何進(jìn)行圖表生成的解決方案,需要的朋友可以參考下
    2023-09-09
  • Springboot傳參詳解

    Springboot傳參詳解

    這篇文章主要介紹了Springboot傳參的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-11-11
  • 使用idea搭建一個(gè)spring mvc項(xiàng)目的圖文教程

    使用idea搭建一個(gè)spring mvc項(xiàng)目的圖文教程

    這篇文章主要介紹了使用idea直接創(chuàng)建一個(gè)spring mvc項(xiàng)目的圖文教程,本文通過(guò)圖文并茂的方式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Java中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式實(shí)現(xiàn)方法詳解

    Java中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了Java中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了Java中綴表達(dá)式轉(zhuǎn)換成后綴表達(dá)式的相關(guān)算法原理與具體實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2019-03-03
  • 深入解讀 Spring Boot 生態(tài)之功能、組件與優(yōu)勢(shì)

    深入解讀 Spring Boot 生態(tài)之功能、組件與優(yōu)勢(shì)

    本文將深入剖析 Spring Boot 的生態(tài)體系,包括其核心功能、生態(tài)組件以及在不同場(chǎng)景中的應(yīng)用,并附上一張 Spring Boot 生態(tài)系統(tǒng)圖,幫助開(kāi)發(fā)者更直觀地理解 Spring Boot 的強(qiáng)大之處,感興趣的朋友一起看看吧
    2024-11-11
  • Java編程cas操作全面解析

    Java編程cas操作全面解析

    這篇文章通過(guò)實(shí)例,解析了Java編程中cas操作的概念、原理以及用法,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-09-09
  • Java中ArrayList初始化的四種方法詳解

    Java中ArrayList初始化的四種方法詳解

    這篇文章主要介紹了Java中ArrayList初始化的四種方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • Java并發(fā)編程中構(gòu)建自定義同步工具

    Java并發(fā)編程中構(gòu)建自定義同步工具

    這篇文章主要介紹了Java并發(fā)編程中構(gòu)建自定義同步工具,本文講解了可阻塞狀態(tài)依賴(lài)操作的結(jié)構(gòu)、有界緩存實(shí)現(xiàn)基類(lèi)示例、阻塞實(shí)現(xiàn)方式一:拋異常給調(diào)用者、阻塞實(shí)現(xiàn)方式二:通過(guò)輪詢(xún)和休眠、阻塞實(shí)現(xiàn)方式三:條件隊(duì)列等內(nèi)容,需要的朋友可以參考下
    2015-04-04
  • Java中快速把map轉(zhuǎn)成json格式的方法

    Java中快速把map轉(zhuǎn)成json格式的方法

    這篇文章主要介紹了Java中快速把map轉(zhuǎn)成json格式的方法,本文使用json-lib.jar中的JSONSerializer.toJSON方法實(shí)現(xiàn)快速把map轉(zhuǎn)換成json,需要的朋友可以參考下
    2015-07-07
  • java實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼

    java實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07

最新評(píng)論

红桥区| 逊克县| 阿克陶县| 万全县| 鲁山县| 武陟县| 永康市| 蕉岭县| 囊谦县| 桓台县| 曲周县| 东城区| 黑山县| 区。| 莆田市| 黑山县| 寿光市| 阿合奇县| 武隆县| 尤溪县| 汤原县| 桃江县| 泗水县| 松溪县| 喜德县| 道孚县| 余江县| 潞西市| 定兴县| 乐亭县| 汉阴县| 田东县| 广东省| 景宁| 晋宁县| 泸溪县| 寻甸| 太保市| 廊坊市| 双柏县| 南昌县|