2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
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
La fonction principale du modèle singleton est de garantir qu'une seule instance d'une classe existe
scènes à utiliser :
● En tant que générateur de numéro de série
● Compteurs de pages Web, pour éviter d'ajouter de la technologie à la base de données à chaque actualisation, mettez-la d'abord en cache
● Créez des objets qui consomment trop de ressources, tels que les connexions d'E/S et de base de données, etc.
Il existe 7 méthodes d'implémentation du modèle singleton
Principalement divisé en style Hungry Man et style Lazy Man
Style chinois affamé : le chargement de classe entraînera la création de l'objet à instance unique
Style paresseux : le chargement de classe n'entraîne pas la création de l'objet à instance unique, mais est créé lorsque l'objet est utilisé pour la première fois.
Voici une démonstration de la meilleure façon d'implémenter le modèle singleton : implémenter le modèle singleton sous la forme d'une énumération et l'utiliser (implémentation d'un générateur de numéro de série)
public enum SequenceGenerator {
INSTANCE;
private int sequenceNumber;
// 构造函数,初始化序列号为0
private SequenceGenerator() {
this.sequenceNumber = 0;
}
/**
* 获取下一个序列号。
* @return 下一个序列号
*/
public synchronized int getNextSequenceNumber() {
return sequenceNumber++;
}
}
// 测试类
public class SequenceGeneratorTest {
public static void main(String[] args) {
// 创建一个线程安全的列表来存储生成的序列号
List<Integer> sequenceNumbers = new CopyOnWriteArrayList<>();
// 创建多个线程来测试并发生成序列号
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 1000; i++) {
executorService.submit(() -> {
int seq = SequenceGenerator.INSTANCE.getNextSequenceNumber();
sequenceNumbers.add(seq);
});
}
executorService.shutdown();
try {
executorService.awaitTermination(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出所有生成的序列号,检查是否有重复
System.out.println(sequenceNumbers);
System.out.println("Total generated sequences: " + sequenceNumbers.size());
}
}
La sortie résultante est
Dans cet exemple, SequenceGenerator est une classe d'énumération qui possède un champ séquenceNumber privé utilisé pour stocker le numéro de séquence actuel. La méthode getNextSequenceNumber est thread-safe car elle est déclarée synchronisée, garantissant ainsi qu'aucun conflit de numéros de séquence ne se produira dans un environnement multithread.
Dans la classe SequenceGeneratorTest, nous utilisons un ExecutorService pour simuler un environnement concurrent et utilisons un CopyOnWriteArrayList thread-safe pour collecter les numéros de séquence générés afin de vérifier l'exactitude des numéros de séquence.
Veuillez noter que bien que le mot-clé synchronisé garantisse la sécurité des threads, il peut affecter les performances dans les scénarios de concurrence élevée. Si le générateur de numéros de séquence doit fonctionner dans des conditions de concurrence très élevée, vous devrez peut-être envisager un algorithme plus efficace, tel que l'utilisation de variables atomiques (telles que AtomicInteger) ou un schéma de génération de numéros de séquence distribués.