Heim  >  Artikel  >  Java  >  Zusammenfassung des Java-Single-Interest-Modells und des Multithreadings

Zusammenfassung des Java-Single-Interest-Modells und des Multithreadings

高洛峰
高洛峰Original
2017-01-05 16:56:541418Durchsuche

Konzept:

Das Singleton-Muster ist ein gängiges Entwurfsmuster in Java. Es gibt drei Arten von Singleton-Mustern: Singleton im Lazy-Stil, Singleton im Hungrig-Stil und Singleton im Registrierungs-Stil.

Das Singleton-Modell weist die folgenden Eigenschaften auf:

1. Eine Singleton-Klasse kann nur eine Instanz haben.

 2. Singleton-Klassen müssen ihre eigene eindeutige Instanz erstellen.

 3. Die Singleton-Klasse muss diese Instanz allen anderen Objekten bereitstellen.

Das Singleton-Muster stellt sicher, dass eine Klasse nur eine Instanz hat, sich selbst instanziiert und diese Instanz dem gesamten System zur Verfügung stellt. In Computersystemen werden Thread-Pools, Caches, Protokollobjekte, Dialogfelder, Drucker und Grafikkartentreiberobjekte häufig als Singletons konzipiert. Diese Anwendungen verfügen alle mehr oder weniger über die Funktionalität von Ressourcenmanagern. Jeder Computer kann über mehrere Drucker verfügen, es kann jedoch nur ein Druckerspooler vorhanden sein, um zu verhindern, dass zwei Druckaufträge gleichzeitig auf dem Drucker ausgegeben werden. Jeder Computer kann über mehrere Kommunikationsanschlüsse verfügen. Das System sollte diese Kommunikationsanschlüsse zentral verwalten, um zu verhindern, dass ein Kommunikationsanschluss gleichzeitig von zwei Anforderungen aufgerufen wird. Kurz gesagt besteht der Zweck der Wahl des Singleton-Modus darin, inkonsistente Zustände und langfristige Richtlinien zu vermeiden.

Hier stellen wir hauptsächlich zwei Typen im Detail vor: Lazy Chinese Style und Hungry Chinese Style

1. Sofortiges Laden/Hungry Chinese Style

In Aufruf Bevor die Methode erstellt wurde, wird die Instanz erstellt, Code:

package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
// 立即加载方式==恶汉模式
private static MyObject myObject = new MyObject();
private MyObject() {
}
public static MyObject getInstance() {
// 此代码版本为立即加载
// 此版本代码的缺点是不能有其他实例变量
// 因为getInstance()方法没有同步
// 所以有可能出现非线程安全的问题
return myObject;
}
}

Thread-Klasse erstellen

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

Lauf erstellen Klasse

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

Laufergebnis

1 167772895
2 167772895
3 167772895

hashCode ist derselbe Ein Wert zeigt an, dass das Objekt ebenfalls dasselbe ist, was darauf hinweist, dass der Single-Interest-Modus für sofortiges Laden implementiert wurde

2. Verzögertes Laden/Lazy-Stil

Die Instanz wird erst geladen, wenn die Methode aufgerufen wird. Die Implementierungslösung kann darin bestehen, die Instanziierung in den parameterlosen Konstruktor einzufügen, sodass die Instanz des Objekts nur erstellt wird, wenn sie aufgerufen wird

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

Thread-Klasse erstellen

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

Laufklasse erstellen

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

Laufendes Ergebnis


1 167772895

Obwohl eine Instanz eines Objekts herausgenommen wird, wenn es sich in einem befindet Multithread-Umgebung, mehrere Instanzen werden angezeigt, es handelt sich also nicht mehr um einen Singleton-Modus


Führen Sie die Testklasse aus

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

2 1224717057

3 1851889404

4 188820504

5 1672864109


Da es ein Problem gibt, müssen wir es im Lazy-Modus lösen, Code:


Der erste Die häufigste Option besteht darin, synchronisiert hinzuzufügen, und synchronisiert kann an verschiedenen Orten hinzugefügt werden


Die erste Option ist die Methodensperre



Dieses synchronisierte Synchronisationsschema führt zu einer zu geringen Effizienz und die gesamte Methode ist gesperrt

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 {
// 模拟在创建对象之前做一些准备性的工作
Thread.sleep(); myObject = new MyObject(); }
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}
Das zweite synchronisierte Nutzungsschema


Diese Methode ist auch sehr ineffizient. Sie müssen nur den Schlüsselcode sperren. Lösung

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 {
// 模拟在创建对象之前做一些准备性的工作
Thread.sleep();
myObject = new MyObject();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}
>

so geschrieben scheint die optimale Lösung zu sein, aber nachdem ich die Ergebnisse ausgeführt hatte, stellte ich fest, dass es tatsächlich nicht threadsicher ist

Ergebnisse:
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 {
// 模拟在创建对象之前做一些准备性的工作
Thread.sleep();
synchronized (MyObject.class) {
myObject = new MyObject();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

1 1224717057

2 971173439

3 1851889404

4 1224717057
5 1672864109

Warum?


Obwohl die Objekterstellungsanweisung gesperrt ist, kann jeweils nur ein Thread die Erstellung abschließen. Wenn jedoch der erste Thread eintrifft, um das Objektobjekt zu erstellen, kann der zweite Thread weiterhin erstellt werden Da wir die create-Anweisung nur fest gesperrt haben, muss zur Lösung dieses Problems







nur ein weiteres Urteil in die Sperre eingefügt werden. Singleton kann garantiert werden . Dies ist der DCL-Doppelprüfmechanismus

Die Ergebnisse sind wie folgt:
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 {
// 模拟在创建对象之前做一些准备性的工作
Thread.sleep();
synchronized (MyObject.class) {
if (myObject == null) {
myObject = new MyObject();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

1 1224717057

2 1224717057

3 1224717057

4 1224717057
5 1224717057

3. Verwenden Sie integrierte statische Klassen, um Singletons zu implementieren

Hauptcode




Thread-Klassencode

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

Klasse ausführen

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

Ergebnis

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

1851889404

1851889404

1851889404

Thread-sicherer Singleton-Modus wird durch interne statische Klassen erreicht

4. Serialisierungs- und Deserialisierungs-Singleton-Modus



Eingebaute statische Klassen können Thread-Sicherheitsprobleme verursachen, aber wenn Sie auf ein serialisiertes Objekt stoßen, ist das durch die Verwendung der Standardmethode erhaltene Ergebnis immer noch Mehrere Instanzen von

MyObject-Code



Business Class

package com.weishiyao.learn.day8.singleton.ep5;
import java.io.Serializable;
public class MyObject implements Serializable {
/**
*
*/
private static final long serialVersionUID = 888L;
// 内部类方式
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("调用了readResolve方法!");
// return MyObjectHandler.myObject;
// }
}

Ergebnis

1 970928725

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

Zwei verschiedene HashCodes, die beweisen, dass es sich nicht um dasselbe Objekt handelt. Fügen Sie zur Lösung den folgenden Codeausschnitt hinzu


wird während der Deserialisierung aufgerufen und Sie können das gleiche Objekt erhalten

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

  protected MyObject readResolve() {
System.out.println("调用了readResolve方法!");
return MyObjectHandler.myObject;
}
Ergebnis

1 1255301379

2 Die readResolve-Methode wurde aufgerufen!

3 1255301379

Derselbe HashCode beweist, dass dasselbe Objekt erhalten wird

5. Verwenden Sie statische Codeblöcke, um Singletons zu implementieren

静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码快这个特性来实现单利模式

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

   

运行结果:

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

通过静态代码块只执行一次的特性也成功的得到了线程安全的单例模式

六、使用enum枚举数据类型实现单例模式

枚举enum和静态代码块的特性类似,在使用枚举时,构造方法会被自动调用,也可以用来实现单例模式

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("调用了MyObject的构造");
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();
}
}

   

运行结果

1 调用了MyObject的构造
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("调用了MyObject的构造");
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());
}
}
}

   

结果

1 调用了MyObject的构造
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

以上总结了单利模式与多线程结合时遇到的各种情况和解决方案,以供以后使用时查阅。

更多Java单利模式与多线程总结归纳相关文章请关注PHP中文网!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn