Condivisione della tecnologia

Modello di progettazione singleton

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Il modello singleton garantisce che una classe abbia una sola istanza, istanzia se stessa e fornisce questa istanza all'intero sistema
La funzione principale del modello singleton è garantire che esista una sola istanza di una classe

scene da utilizzare:
● Come generatore di numeri di serie
● I contatori delle pagine Web, per evitare di aggiungere tecnologia al database ogni volta che viene aggiornato, memorizzarlo prima nella cache
● Creare oggetti che consumano troppe risorse, come I/O e connessioni al database, ecc.

Esistono 7 metodi di implementazione del modello singleton
Principalmente diviso in stile Hungry Man e stile Lazy Man
Stile cinese affamato: il caricamento della classe causerà la creazione dell'oggetto a istanza singola
Stile lazy: il caricamento della classe non provoca la creazione dell'oggetto a istanza singola, ma viene creato quando l'oggetto viene utilizzato per la prima volta.

Ecco una dimostrazione del modo migliore per implementare il modello singleton: implementare il modello singleton sotto forma di enumerazione e utilizzarlo (implementando un generatore di numeri seriali)

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());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

L'output risultante è
Inserisci qui la descrizione dell'immagine

In questo esempio, SequenceGenerator è una classe di enumerazione che dispone di un campo sequenceNumber privato utilizzato per archiviare il numero di sequenza corrente. Il metodo getNextSequenceNumber è thread-safe poiché è dichiarato sincronizzato, garantendo che non si verifichino conflitti tra numeri di sequenza in un ambiente multi-thread.
Nella classe SequenceGeneratorTest, utilizziamo un ExecutorService per simulare un ambiente simultaneo e utilizziamo un CopyOnWriteArrayList thread-safe per raccogliere i numeri di sequenza generati al fine di verificare la correttezza dei numeri di sequenza.
Tieni presente che, sebbene la parola chiave sincronizzata garantisca la sicurezza del thread, potrebbe influire sulle prestazioni in scenari ad alta concorrenza. Se il generatore di numeri di sequenza deve funzionare con una concorrenza molto elevata, potrebbe essere necessario prendere in considerazione un algoritmo più efficiente, come l'utilizzo di variabili atomiche (come AtomicInteger) o uno schema di generazione di numeri di sequenza distribuiti.