Maison > Java > javaDidacticiel > Résumé du modèle Java à intérêt unique et multithread

Résumé du modèle Java à intérêt unique et multithread

高洛峰
Libérer: 2017-01-05 16:56:54
original
1438 Les gens l'ont consulté

Concept :

Le modèle singleton est un modèle de conception courant en Java. Il existe trois types de modèles singleton : le singleton de style paresseux, le singleton de style affamé et le singleton de style d'enregistrement.

Le mode singleton a les caractéristiques suivantes :

1. Une classe singleton ne peut avoir qu'une seule instance.

 2. Les classes Singleton doivent créer leur propre instance unique.

 3. La classe singleton doit fournir cette instance à tous les autres objets.

Le modèle singleton garantit qu'une classe n'a qu'une seule instance, s'instancie et fournit cette instance à l'ensemble du système. Dans les systèmes informatiques, les pools de threads, les caches, les objets de journal, les boîtes de dialogue, les imprimantes et les objets pilotes de carte graphique sont souvent conçus comme des singletons. Ces applications disposent toutes plus ou moins des fonctionnalités de gestionnaires de ressources. Chaque ordinateur peut avoir plusieurs imprimantes, mais il ne peut y avoir qu'un seul spouleur d'imprimante pour empêcher que deux travaux d'impression ne soient envoyés simultanément sur l'imprimante. Chaque ordinateur peut avoir plusieurs ports de communication, et le système doit gérer ces ports de communication de manière centralisée pour empêcher qu'un port de communication soit appelé par deux requêtes en même temps. En bref, le but du choix du mode singleton est d'éviter les états incohérents et d'éviter les politiques à long terme.

Ici, nous présentons principalement deux types en détail : le style chinois paresseux et le style chinois affamé

1. Chargement immédiat/style chinois affamé

En appelant Avant que la méthode, l'instance ait été créée, codez :

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;
}
}
Copier après la connexion
Créer une classe de thread

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

Créer une classe en cours d'exécution classe

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();
}
}
Copier après la connexion

Résultat d'exécution


1 167772895

2 167772895
3 167772895

hashCode est le même Une valeur indique que l'objet est également le même, indiquant que le mode de chargement immédiat à intérêt unique a été implémenté


2. Chargement différé/style paresseux


L'instance n'est pas chargée tant que la méthode n'est pas créée. La solution d'implémentation peut être de placer l'instanciation dans le constructeur sans paramètre, de sorte que l'instance de l'objet ne soit créée que lorsqu'elle est appelée. Code :

.

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;
}
}
Copier après la connexion

Créer une classe de thread

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

Créer une classe d'exécution

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

Résultat d'exécution


1 167772895

Bien qu'une instance d'un objet soit supprimée, si elle se trouve dans un environnement multithread, plusieurs instances apparaîtront, donc ce n'est plus un mode singleton


Exécuter la classe de test

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();
}
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
1 980258163

2 1224717057

3 1851889404

4 188820504

5 1672864109


Puisqu'il y a un problème, il faut le résoudre La solution multithread en mode paresseux, code :


Le premier. L'option, la plus courante, consiste à ajouter synchronisé, et synchronisé peut être ajouté à différents emplacements


La première option est le verrouillage de méthode



Ce schéma de synchronisation synchronisé entraîne une efficacité trop faible et la méthode entière est verrouillée

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;
}
}
Copier après la connexion
Le deuxième schéma d'utilisation synchronisé


Cette méthode est également très inefficace. Tous les codes de la méthode sont verrouillés. Seul le code clé doit être verrouillé. Le troisième type de synchronisation est utilisé. Solution

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;
}
}
Copier après la connexion

.

écrit comme ceci semble être la solution optimale, mais après avoir exécuté les résultats, j'ai découvert qu'il n'était en fait pas thread-safe

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;
}
}
Copier après la connexion
Résultats :

1 1224717057

2 971173439

3 1851889404
4 1224717057

5 1672864109

Pourquoi ?

Bien que l'instruction de création d'objet soit verrouillée, un seul thread peut terminer la création à la fois. Cependant, lorsque le premier thread arrive pour créer l'objet Object, le deuxième thread peut toujours continuer. , parce que nous avons uniquement verrouillé l'instruction create, la solution à ce problème





n'a besoin que d'ajouter un autre jugement dans le verrou, Singleton peut être garanti. Il s'agit du mécanisme de double vérification DCL

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;
}
}
Copier après la connexion
Les résultats sont les suivants :

1 1224717057

2 1224717057

3 1224717057
4 1224717057

5 1224717057


3. Utilisez des classes statiques intégrées pour implémenter des singletons


Code principal



Code de classe de fil

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;
}
}
Copier après la connexion

Classe d'exécution

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

Résultat

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();
}
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
1851889404

1851889404

1851889404

1851889404

1851889404


Le mode singleton thread-safe est obtenu grâce à des classes statiques internes


4. Mode singleton de sérialisation et de désérialisation


Les classes statiques intégrées peuvent poser des problèmes de sécurité des threads, mais si vous rencontrez un objet sérialisé, le résultat obtenu en utilisant la méthode par défaut est toujours Plusieurs instances de


Code MonObjet



Classe Affaires

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;
// }
}
Copier après la connexion

Résultat

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();
}
}
}
Copier après la connexion
1 970928725

2 1099149023

Deux hashCode différents, prouvant qu'il ne s'agit pas du même objet Solution, ajoutez l'extrait de code suivant <🎜. >



est appelé lors de la désérialisation et vous pouvez obtenir le même objet

System.out.println (myObject.readResolve() .hashCode());
  protected MyObject readResolve() {
System.out.println("调用了readResolve方法!");
return MyObjectHandler.myObject;
}
Copier après la connexion

Result

1 1255301379

2 La méthode readResolve a été appelée !
3 1255301379

Le même hashCode prouve que le même objet est obtenu


5. Utilisez des blocs de code statiques pour implémenter des singletons

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

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;
}
}
Copier après la connexion

线程类

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());
}
}
}
Copier après la connexion

运行类

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();
}
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

运行结果:

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;
}
}
Copier après la connexion

线程类

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());
}
}
}
Copier après la connexion

运行类

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();
}
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

运行结果

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();
}
}
Copier après la connexion

更改线程代码

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());
}
}
}
Copier après la connexion

   

结果

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中文网!


Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal