Java Academy · Oppitunti

Singleton: säieturvalliset toteutukset

Rakenna säieturvallinen Singleton double-checked locking-, enum- tai holder-mallilla.

Oppitunti 1/413 vaihetta

Singleton: säieturvalliset toteutukset on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.

Singleton-malli

Singleton takaa, että luokasta on JVM:ssä olemassa vain yksi instanssi. Yleisiä käyttökohteita ovat määritysten hallinta, yhteyspoolit ja lokituspalvelut.

Naiivi Singleton — ei säieturvallinen

Klassinen laiskasti alustettava singleton ei toimi samanaikaisessa käytössä: kaksi säiettä voi läpäistä null-tarkistuksen yhtä aikaa ja luoda kaksi instanssia.

public class Config {
    private static Config instance;
    private Config() {}
    public static Config getInstance() {
        if (instance == null) {              // race condition!
            instance = new Config();
        }
        return instance;
    }
}

synchronized-metodi — yksinkertainen mutta hidas

Kun synchronized lisätään metodiin getInstance(), siitä tulee säieturvallinen, mutta lukitus tehdään jokaisella kutsulla, vaikka instanssi olisi jo olemassa — tämä aiheuttaa tarpeetonta kuormaa.

public static synchronized Config getInstance() {
    if (instance == null) instance = new Config();
    return instance;
}

Kaksinkertainen tarkistus lukituksen kanssa

Tehkää tarkistus ilman lukitusta ja tarkistakaa sitten uudelleen synchronized-lohkon sisällä. Kentässä on käytettävä volatile-määrettä käskyjen uudelleenjärjestämisen estämiseksi.

public class Config {
    private static volatile Config instance;
    private Config() {}
    public static Config getInstance() {
        if (instance == null) {
            synchronized (Config.class) {
                if (instance == null) instance = new Config();
            }
        }
        return instance;
    }
}

Initialization-on-Demand Holder

Turvallisin ja tehokkain laiskasti alustettava singleton on yksityinen staattinen sisäkkäinen luokka, joka sisältää instanssin. JVM lataa sen vasta, kun getInstance()-metodia kutsutaan ensimmäisen kerran — luokan lataus on luonnostaan säieturvallista.

public class Config {
    private Config() {}
    private static final class Holder {
        static final Config INSTANCE = new Config();
    }
    public static Config getInstance() {
        return Holder.INSTANCE;
    }
}

Enum-Singleton

Effective Java suosittelee enumeraatiota, jossa on yksi vakio. Ratkaisu on tiivis, säieturvallinen ja turvallinen serialisoinnin kannalta sekä immuuni reflektiohyökkäyksille.

public enum AppConfig {
    INSTANCE;
    private String apiUrl = "https://api.example.com";
    public String getApiUrl() { return apiUrl; }
}
// Usage:
String url = AppConfig.INSTANCE.getApiUrl();

Ennakoiva alustaminen

Jos käynnistyksen aikainen kustannus on hyväksyttävä, alustakaa instanssi luokan lataamisen yhteydessä static final-kentässä. Ratkaisu on yksinkertainen ja säieturvallinen, mutta instanssi luodaan aina, vaikka sitä ei koskaan käytettäisi.

public class Config {
    private static final Config INSTANCE = new Config();
    private Config() {}
    public static Config getInstance() { return INSTANCE; }
}

Singleton ja serialisointi

Serialisoidusta ja sitten deserialisoidusta singletonista syntyy uusi instanssi, ellette lisää readResolve()-metodia, joka palauttaa arvon INSTANCE. Enumeraatioon perustuva ratkaisu hoitaa tämän automaattisesti.

private Object readResolve() { return INSTANCE; }

Singleton ja reflektiohyökkäykset

Reflektio voi kutsua yksityisiä konstruktoreita. Suojautukaa tältä heittämällä konstruktorissa poikkeus, jos instanssi on jo olemassa. Enum-singletonit ovat JVM-määrityksen mukaan immuuneja tälle.

private Config() {
    if (Holder.INSTANCE != null) {
        throw new IllegalStateException("Use getInstance()");
    }
}

Singleton riippuvuuksien injektointikehyksissä

Springissä beanit ovat oletusarvoisesti singleton-instansseja (@Scope("singleton")). Singleton-mallia tarvitsee harvoin toteuttaa itse, sillä DI-kontainerin kannattaa antaa hallita sitä.

@Component  // Spring manages a single instance
public class FeatureFlags {
    private final boolean darkMode = true;
    public boolean isDarkMode() { return darkMode; }
}

Singletonien testaaminen

Singletonien yksikkötestaus on vaikeaa, koska ne sisältävät globaalia tilaa. Suosikaa itse kirjoitetun Singleton-koodin sijaan riippuvuuksien injektointia ja injektoikaa testeissä mock-instanssit konstruktorin kautta.

Pikatarkistus

Mitä singleton-ratkaisua Effective Java suosittelee?

Kertaus

Säieturvallisissa singleto­neissa käyttäkää Initialization-on-Demand Holder- tai enumeraatiopohjaista ratkaisua. Välttäkää naiivia laiskaa alustamista. Spring-sovelluksissa antakaa kehyksen hallita skoopin hallintaa.

Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
104
Oppitunnit
374

Usein kysytyt kysymykset

Onko oppitunti ”Singleton: säieturvalliset toteutukset” ilmainen?

Kyllä – oppitunnin ”Singleton: säieturvalliset toteutukset” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Singleton: säieturvalliset toteutukset”?

Rakenna säieturvallinen Singleton double-checked locking-, enum- tai holder-mallilla. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.

Kuinka kauan ”Singleton: säieturvalliset toteutukset”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?

Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Singleton: säieturvalliset toteutukset
  2. Factory Method -suunnittelumalli
  3. Abstract Factory tuoteperheille
  4. Builder-malli fluent-rajapinnalla
← Takaisin: Java Academy