Vra

Ek probeer om te hou op 'n probleem in ons stelsel en die volgende kode bekommer my. Die volgende plaasvind in ons doPost () metode in die primêre Servlet (name is verander om die skuldiges te beskerm):

...
if(Single.getInstance().firstTime()){
   doPreperations();
}
normalResponse();
...

Die Singleton 'Enkel' lyk soos volg:

private static Single theInstance = new Single();

private Single() {
...load properties...
}

public static Single getInstance() {
    return theInstance;
}

Met die manier waarop dit is ingestel op 'n statiese inisialiseerder gebruik in plaas van die beheer van 'n nul theInstance in die metode getInstance (), kan hierdie ontslae herbou oor en oor weer?

PS - Ons loop WebSphere 6 met die App op Java 1.4

Was dit nuttig?

Oplossing

Ek het gevind dat hierdie op die terrein Sun se:

  

meerdere single Terselfdertyd Loaded deur ander klas Loaders

     

Wanneer twee klas loaders te laai 'n klas,   jy eintlik twee afskrifte van die   klas, en elkeen kan sy eie te hê   Singleton byvoorbeeld. dit is   veral relevant in servlets   loop in sekere Servlet enjins   (IPlanet byvoorbeeld), waar elke   Servlet by verstek gebruik sy eie klas   loader. Twee verskillende servlets   toegang tot 'n gesamentlike Singleton sal, in   Trouens, kry twee verskillende voorwerpe.

     

Verskeie klas loaders voorkom meer   algemeen as wat jy dink. Wanneer   blaaiers vrag klasse van die netwerk   vir gebruik deur applets, hulle gebruik 'n   afsonderlike klas loader vir elke bediener   adres. Net so, Jini en RMI   stelsels kan 'n aparte klas gebruik   loader vir die verskillende kode basisse   waaruit hulle aflaai klas lêers.   As jou eie stelsel gebruik persoonlike klas   loaders, almal dieselfde kwessies kan   ontstaan.

     

As gelaai deur verskillende klas loaders,   twee klasse met dieselfde naam, selfs   dieselfde naam pakket, word beskou as   duidelike - selfs al is, in werklikheid, hulle is   byte-for-byte dieselfde klas. Die   ander klas loaders verteenwoordig   verskillende naamruimtes wat onderskei   klasse (selfs al is die klasse '   name is dieselfde), sodat die twee   MySingleton klasse is in werklikheid   duidelike. (Sien "Klas Loaders as 'n   Naamruimte Meganisme "in Resources.)   Sedert twee Singleton voorwerpe behoort aan   twee klasse van dieselfde naam, sal dit   verskyn die eerste oogopslag dat daar   twee Singleton voorwerpe van dieselfde   klas.

Citation .

In bykomend tot die bogenoemde probleem, as firstTime() nie gesinchroniseer, jy kan threading kwessies het daar so goed.

Ander wenke

Nee, dit sal nie gebou kry oor en oor weer. Dit is staties, so dit slegs een keer sal gebou word, reg wanneer die klas geraak vir die eerste keer deur die Classloader.

enigste uitsondering -. As jy gebeur om verskeie Classloaders het

( GeekAndPoke ):

alt text

As ander genoem het, die statiese inisialiseerder sal slegs een keer uitgevoer word per classloader.

Een ding wat ek sou 'n blik op die firstTime() metode - hoekom kan nie die werk in doPreparations() binne die Singleton self

hanteer

Dit klink na 'n nare stel afhanklikhede.

Daar is absoluut geen verskil tussen die gebruik van 'n statiese inisialiseerder en lui inisialisering. In werklikheid is dit baie makliker om te mors op die lui inisialisering, wat ook dwing sinchronisasie. Die JVM waarborg dat die statiese inisialiseerder altyd uitgevoer word voordat die klas is toeganklik en dit sal vir eens en slegs een keer gebeur.

Dit gesê JVM nie waarborg dat jou klas net een keer sal gelaai word nie. Maar selfs al is dit meer as een keer gelaai, sal jou web-program nog sien net die relevante Singleton, as dit nie in die web-program classloader of sy ouer sal gelaai word nie. As jy 'n paar web aansoek ontplooi, dan firstTime () sal een keer vir elke aansoek genoem.

Die mees klaarblyklike dinge om te kyk is dat firstTime () moet gesinchroniseer en dat die firstTime vlag is ingestel voor die verlaat van hierdie metode.

Nee, dit sal nie veelvuldige kopieë van 'Enkel' skep. (Classloader kwessie sal later besoek word)

Die implementering jy uiteengesit word beskryf as 'gretig inisialisering' deur in boek Briant Goetz se - ' Java Concurrency in praktyk '.

public class Single
{
    private static Single theInstance = new Single();

    private Single() 
    { 
        // load properties
    }

    public static Single getInstance() 
    {
        return theInstance;
    }
}

Die kode is nie wat jy wou. Jou kode is besig om lui-inisialisering te voer na die geval is geskep. Dit vereis dat alle die kliënt biblioteek om 'firstTime () / doPreparation ()' uit te voer voordat dit gebruik word. Jy gaan om te vertrou op die kliënt om regte ding wat die kode baie broos maak doen.

Jy kan die kode te verander as die volgende so daar sal nie enige duplikaat kode.

public class Single
{
    private static Single theInstance = new Single();

    private Single() 
    { 
        // load properties
    }

    public static Single getInstance() 
    {   
        // check for initialization of theInstance
        if ( theInstance.firstTime() )
           theInstance.doPreparation();

        return theInstance;
    }
}

Ongelukkig is dit 'n swak implementering van lui inisialisering en dit sal nie werk nie in konkurrente omgewing (soos J2EE houer).

Daar is baie artikels geskryf oor Singleton inisialisering, spesifiek op die geheue model. JSR 133 aangespreek baie swakheid in Java geheue model in Java 1.5 en 1.6.

Met Java 1.5 & 1.6, jy het 'n paar keuses en hulle word genoem in die boek ' Doeltreffende Java 'deur Josua Bloch.

  1. Gretig Initialziation, soos die bokant [EJ Item 3]
  2. Lazy Initalization Holder Klas idioom [EJ Item 71]
  3. Enum tipe [EJ Item 3]
  4. dubbel gekontroleer sluiting met 'vlugtige 'n statiese veld [EJ Item 71]

Oplossing 3 en 4 sal slegs werk in Java 1.5 en hoër. So die beste oplossing sou wees # 2.

Hier is die psuedo-implementering.

public class Single
{
    private static class SingleHolder
    {
        public static Single theInstance = new Single();
    }

    private Single() 
    { 
        // load properties
        doPreparation();
    }

    public static Single getInstance() 
    {
        return SingleHolder.theInstance;
    }
}

Let daarop dat 'doPreparation ()' is binnekant van die konstruktor so jy waarborg aan die behoorlik geïnisialiseer byvoorbeeld kry. Ook, is jy piggying terug op lui klas laai JVM se en doen enige sinkronisasie 'getInstance ()' nie nodig het nie.

Een ding wat jy opgemerk dat statiese veld theInstance is nie 'n finale ". Die voorbeeld op Java Concurrency nie" finale "het maar EJ doen. Miskien James se kan meer kleur aan sy antwoord op 'classloader en vereiste van "finale" om korrektheid te verseker,

Noudat dit gesê is, is daar 'n newe-effek wat met behulp van 'n statiese finale ". Java samesteller is baie aggressief wanneer dit sien 'n statiese finale en probeer om dit so veel as moontlik inline. Dit is genoem op n blog boodskap deur Jeremy Manson .

Hier is 'n eenvoudige voorbeeld.

lêer: A.java

public class A
{
    final static String word = "Hello World";
}

lêer: B.java

public class B
{
    public static void main(String[] args) {
        System.out.println(A.word);
    }
}

As jy beide A.java en B.java stel, A.java verander jy na volgende.

lêer: A.java

public class A
{
    final static String word = "Goodbye World";
}

Jy heropstel 'A.java en tik B.class. Die uitset wat jy sou kry is

Hello World

As vir die classloader kwessie, die antwoord is ja, jy kan meer as een geval van Singleton in verskeie classloaders het. Jy kan meer inligting oor wikipedia vind. Daar is ook 'n spesifieke artikel oor Websphere .

Die enigste ding wat ek wil hê dat Singleton implementering (behalwe nie met behulp van 'n Singleton enigsins) verander oor is om die geval veld finale maak. Die statiese veld sal weer geïnisialiseer word, op klas vrag. Sedert klasse lui gelaai, jy effektief kry lui Instantiëring gratis.

Natuurlik, as dit gelaai uit afsonderlike klas loaders kry jy verskeie "single", maar dit is 'n beperking van elke Singleton idioom in Java.

wysig : Die firstTime () en doPreparations () stukkies hoef te kyk verdagte though. Kan hulle nie wankel in die konstruktor van die Singleton byvoorbeeld?

Nee - die statiese inisialisering van die instance sal altyd net een keer gedoen. Twee dinge om te oorweeg:

  • Dit is nie draad-veilige (die geval is nie "gepubliseer" te hoofgeheue)
  • Jou firstTime metode is waarskynlik meer as een keer genoem word, tensy behoorlik gesinchroniseer

In teorie is dit sal net een keer gebou. Maar hierdie patroon breek in verskillende aansoek bedieners, waar jy verskeie gevalle van 'Singleton' klasse (aangesien hulle nie ryg-veilige).

kan kry

Ook die Singleton patroon is critized baie. Sien byvoorbeeld Singleton Ek is lief vir jou, maar jy my afbring

Dit sal kry net een keer gelaai word wanneer die klas is gelaai met die classloader. Hierdie voorbeeld gee 'n beter Singleton implementering egter dis as lui-gelaai as moontlik en draad-veilige. Verder, dit werk in alle bekende weergawes van Java. Hierdie oplossing is die mees draagbare oor verskillende Java opstellers en virtuele masjiene.


public class Single {

private static class SingleHolder {
   private static final Single INSTANCE = new Single();
}

private Single() {
...load properties...
}

public static Single getInstance() {
    return SingleHolder.INSTANCE;
}

}

Die innerlike klas is nie vroeër gekla (en dus nie vroeër deur die klas loader laai) as die oomblik dat getInstance () genoem word. So, hierdie oplossing is draad-veilige sonder dat spesiale taalkonstrukte (maw vlugtige en / of gesinchroniseer).

Dit is nie verpligtend vir die enkele geval om finaal (dit is nie 'n goeie idee te alle inderdaad, want dit sal verhoed dat jy om te skakel is dit gedrag met behulp van ander patrone).

In die kode hieronder kan jy sien hoe dit slegs een keer kry aangehaal (eerste keer wat jy die konstruktor noem)

pakket datum;

invoer java.util.Date;

openbare klas USDateFactory implemente DateFactory {     private statiese USDateFactory usdatefactory = null

private USDateFactory () { }

public static USDateFactory getUsdatefactory() {
    if(usdatefactory==null) {
        usdatefactory = new USDateFactory();
    }
    return usdatefactory;
}

public String getTextDate (Date date) {
    return null;
}

public NumericalDate getNumericalDate (Date date) {
    return null;
}

}

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top