欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

概念:

  java中單例模式是一種常見的設計模式,單例模式分三種:懶漢式單例、餓漢式單例、登記式單例三種。

  單例模式有一下特點:

  1、單例類只能有一個實例。

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

  3、單例類必須給所有其他對象提供這一實例。

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

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

一、立即加載/餓漢式

在調(diào)用方法前,實例就已經(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() {
// 此代碼版本為立即加載
// 此版本代碼的缺點是不能有其他實例變量
// 因為getInstance()方法沒有同步
// 所以有可能出現(xiàn)非線程安全的問題
return myObject;
}
}

創(chuàng)建線程類

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

創(chuàng)建運行類

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();
}
}

運行結(jié)果

1 167772895
2 167772895
3 167772895

hashCode是同一個值,說明對象也是同一個,說明實現(xiàn)了立即加載型的單利模式

二、延遲加載/懶漢式

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

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)建線程類

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

創(chuàng)建運行類

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

運行結(jié)果

1 167772895

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

運行測試類

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é)果

1 980258163
2 1224717057
3 1851889404
4 188820504
5 1672864109

既然出現(xià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)建對象之前做一些準備性的工作
Thread.sleep(); myObject = new MyObject(); }
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
} 

這種synchronized的同步方案導致效率過于低下,整個方法都被鎖住

第二種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)建對象之前做一些準備性的工作
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)建對象之前做一些準備性的工作
Thread.sleep();
synchronized (MyObject.class) {
myObject = new MyObject();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
} 

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

結(jié)果:

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

雖然鎖住了對象創(chuàng)建的語句,每次只能有一個線程完成創(chuàng)建,但是,當?shù)谝粋€線程進來創(chuàng)建完成Object對象以后,第二個線程進來還是可以繼續(xù)創(chuàng)建的,因為我們緊緊只鎖住了創(chuàng)建語句,這個問題解決方案

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)建對象之前做一些準備性的工作
Thread.sleep();
synchronized (MyObject.class) {
if (myObject == null) {
myObject = new MyObject();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

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

結(jié)果如下:

1 1224717057
2 1224717057
3 1224717057
4 1224717057
5 1224717057

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

主要代碼

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

線程類代碼

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

運行類

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

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

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

內(nèi)置靜態(tài)類可以達到線程安全的問題,但如果遇到序列化對象時,使用默認方式得到的結(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)部類方式
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è)務類

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

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

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

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

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

結(jié)果

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

相同的hashCode,證明得到了同一個對象

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

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

MyObject類

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;
}
}

線程類

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());
}
}
}

運行類

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é)果:

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

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

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

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

MyObject類

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;
}
}

線程類

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());
}
}
}

運行類

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é)果

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

上面這種寫法將枚舉類暴露了,違反了“職責單一原則”,可以使用一個類將枚舉包裹起來

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é)合時遇到的各種情況和解決方案,以供以后使用時查閱。

相關(guān)文章

  • scala 讀取txt文件的方法示例

    scala 讀取txt文件的方法示例

    這篇文章主要介紹了scala 讀取txt文件的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-06-06
  • Springboot整合Shiro的代碼實例

    Springboot整合Shiro的代碼實例

    這篇文章主要介紹了Springboot整合Shiro的代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • Spring中七種事務傳播機制詳解

    Spring中七種事務傳播機制詳解

    這篇文章主要介紹了Spring中七種事務傳播機制詳解,Spring在TransactionDefinition接口中規(guī)定了7種類型的事務傳播行為,Propagation枚舉則引用了這些類型,開發(fā)過程中我們一般直接用Propagation枚舉,需要的朋友可以參考下
    2024-01-01
  • java應用cpu占用過高問題分析及解決方法

    java應用cpu占用過高問題分析及解決方法

    這篇文章主要介紹了java應用cpu占用過高問題分析及解決方法,具有一定參考價值,需要的朋友可以參考下。
    2017-09-09
  • springboot?如何解決yml沒有spring的小葉子標志問題

    springboot?如何解決yml沒有spring的小葉子標志問題

    這篇文章主要介紹了springboot?如何解決yml沒有spring的小葉子標志問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 對Mybatis?Plus中@TableField的使用正解

    對Mybatis?Plus中@TableField的使用正解

    這篇文章主要介紹了對Mybatis?Plus中@TableField的使用正解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • SpringBoot實現(xiàn)異步事件Event詳解

    SpringBoot實現(xiàn)異步事件Event詳解

    這篇文章主要介紹了SpringBoot實現(xiàn)異步事件Event詳解,異步事件的模式,通常將一些非主要的業(yè)務放在監(jiān)聽器中執(zhí)行,因為監(jiān)聽器中存在失敗的風險,所以使用的時候需要注意,需要的朋友可以參考下
    2023-11-11
  • Spark Streaming算子開發(fā)實例

    Spark Streaming算子開發(fā)實例

    這篇文章主要介紹了Spark Streaming算子開發(fā)實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-06-06
  • MybatisPlus修改時空字段無法修改的解決方案

    MybatisPlus修改時空字段無法修改的解決方案

    這篇文章主要介紹了MybatisPlus修改時空字段無法修改的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Spring Boot 定義系統(tǒng)啟動任務的多種方式

    Spring Boot 定義系統(tǒng)啟動任務的多種方式

    這篇文章主要介紹了Spring Boot 定義系統(tǒng)啟動任務的多種方式,看看你都會哪幾種 ,感興趣的朋友跟隨小編一起看看吧
    2019-04-04

最新評論