Sei sulla pagina 1di 8

CP pensareprogettareprogrammare n.

142 gennaio 2004

Il processo di inizializzazione in Java


parte 1

di Guido Anselmi
Tutto quello che accade nella JVM durante linizializzazione di una classe o interfaccia Java

Guido Anselmi Laureato in Ingegneria Informatica, si interessa da molti anni di programmazione Object Oriented. Attualmente si occupa di formazione ` Java e di qualita del software presso una ` importante societa nanziaria di Milano.

pubblicato su WWW.INFOMEDIA.IT stampa digitale da Lulu Enterprises Inc. stores.lulu.com/infomedia


Infomedia
` Infomedia e limpresa editoriale che da quasi venti anni ha raccolto la voce dei programmatori, dei sistemisti, dei professionisti, degli studenti, dei ricercatori e dei professori dinformatica italiani. Sono pi` di 800 gli autori che hanno realizzato per le teu state Computer Programming, Dev, Login, Visual Basic Journal e Java Journal, molte migliaia di articoli tecnici, presentazioni di prodotti, tecnologie, protocolli, strumenti di lavoro, tecniche di sviluppo e semplici trucchi e stratagemmi. Oltre 6 milioni di copie distribuite, trentamila pagine stampate, fanno di questa impresa la pi` grande ed u inuente realt` delleditoria specializzata nel campo della a programmazione e della sistemistica. In tutti questi anni le riviste Infomedia hanno vissuto della passione di quanti vedono nella programmazione non solo la propria professione ma unattivit` vitale e un vero a divertimento. ` Nel 2009, Infomedia e cambiata radicalmente adottando ` un nuovo modello aziendale ed editoriale e si e organizzata attorno ad una idea di Impresa Sociale di Comunit` , a partecipata da programmatori e sistemisti, separando le attivit` di gestione dellinformazione gestite da un board a comunitario professionale e quelle di produzione gesti` te da una impresa strumentale. Questo assetto e in linea con le migliori esperienze internazionali e rende Infomedia ancora di pi` parte della Comunit` nazionale degli u a sviluppatori di software. ` Infomedia e media-partner di manifestazioni ed eventi in ambito informatico, collabora con molti dei pi` imporu tanti editori informatici italiani come partner editoriale e fornitore di servizi di localizzazione in italiano di testi in lingua inglese.

Limpaginazione automatica di questa rivista e realizzata al ` 100% con strumenti Open Source usando OpenOffice, Emacs, BHL, LaTeX, Gimp, Inkscape e i linguaggi Lisp, Python e BASH

For copyright information about the contents of Computer Programming, please see the section Copyright at the end of each article if exists, otherwise ask authors. Infomedia contents is 2004 Infomedia and released as Creative Commons 2.5 BY-NC-ND. Turing Club content is 2004 Turing Club released as Creative Commons 2.5 BY-ND. Le informazioni di copyright sul contenuto di Computer Programming sono riportate nella sezione Copyright alla ne di ciascun articolo o vanno richieste direttamente agli autori. Il contenuto Infomedia e 2004 Infome` dia e rilasciato con Licenza Creative Commons 2.5 BYNC-ND. Il contenuto Turing Club e 2004 Turing Club ` e rilasciato con Licenza Creative Commons 2.5 BY-ND. Si applicano tutte le norme di tutela dei marchi e dei segni distintivi. ` E in ogni caso ammessa la riproduzione parziale o totale dei testi e delle immagini per scopo didattico purch e vengano integralmente citati gli autori e la completa identicazione della testata. Manoscritti e foto originali, anche se non pubblicati, non si restituiscono. Contenuto pubblicitario inferiore al 45%. La biograa dellautore riportata nellarticolo e sul sito www.infomedia.it e di norma quella disponibi` le nella stampa dellarticolo o aggiornata a cura dellautore stesso. Per aggiornarla scrivere a info@infomedia.it o farlo in autonomia allindirizzo http://mags.programmers.net/moduli/biograa

linguaggi

Il processo di inizializzazione in Java


Tutto quello che accade nella JVM durante linizializzazione di una classe o interfaccia Java
di Guido Anselmi

Prima Parte

copo del presente articolo la descrizione dettagliata del processo di inizializzazione dei tipi non primitivi in unapplicazione Java. Tale processo, spesso ignorato o sottovalutato dai programmatori, un meccanismo molto complesso e per certi versi raffinato, la cui conoscenza approfondita pu essere daiuto nella realizzazione di applicazioni correttamente funzionanti.

FIGURA 1

Loading dei tipi

Prima dellinizializzazione: loading dei tipi


Le classi ed interfacce Java sono rese disponibili al programma in esecuzione attraverso tre fasi distinte: loading, linking ed initialization, che devono essere eseguite in questordine rigoroso (Figura 1). La prima fase, quella di loading, corrisponde allestrazione dei dati binari dal file con estensione .class che rappresenta il tipo in questione ed al loro caricamento nella JVM in esecuzione. Naturalmente il formato binario di tali dati deve aderire alle specifiche dei class file, ma una particolare implementazione di una JVM libera, qualora i progettisti ne sentissero la necessit, di caricare i tipi anche a partire da altri formati binari realizzati appositamente (ad esempio per ragioni di maggiore efficienza o compattezza). In tale fase la JVM, tipicamente sfruttando le indicazioni contenute nella variabile di ambiente CLASSPATH, accede ai dati binari sul file system, ne effettua il parsing e li carica nelle opportune aree di memoria. Si noti comunque che le specifiche della

Guido Anselmi

ganselmi@infomedia.it

Laureato in Ingegneria Informatica, si interessa da molti anni di programmazione Object Oriented. Attualmente si occupa di formazione Java e di qualit del software presso una importante societ finanziaria di Milano.

JVM non dicono in alcun modo dove i dati rappresentanti un tipo vadano conservati, quindi nessuno vieterebbe di realizzare una JVM che prenda tali dati ad esempio da un database proprietario. Larea di memoria designata a contenere tutte le informazioni sui tipi Java denominata Method Area. In essa viene conservata la descrizione completa di ogni tipo caricato in memoria per una data applicazione. Tali informazioni conterranno il nome del tipo, il nome della superclasse diretta (a meno che il tipo sia Object o una interfaccia), una lista ordinata di tutte le superinterfacce direttamente implementate, oltre che il modificatore daccesso del tipo. Fanno parte della Method Area anche la descrizione dei field e dei metodi dichiarati nel tipo; per i field tali informazioni consistono essenzialmente in nome, modificatore daccesso e tipo, mentre per i metodi ci saranno anche il nome del tipo eventualmente ritornato (oppure void), la lista con nomi e tipo dei parametri, il bytecode corrispondente al codice del metodo ed infine il modificatore daccesso. Tra i class data di ciascun tipo nella Method Area trovano logicamente posto anche tutte le variabili di classe del tipo (ossia quelle dichiarate con il modifi-

44

Computer Programming n. 142 - Gennaio 2004

PROGRAMMING
TABELLA 1 I valori di default

Tipo int long short char byte boolean reference float double

Valore default 0 0L (short)0 \u0000 0 false null 0.0f 0.0d

la verifica che non ci siano dichiarazioni di metodi incompatibili, ad esempio due metodi con ugual nome e lista dei parametri, ma differente tipo di ritorno; la verifica dellintegrit del bytecode, ad esempio sincerandosi che nessuna istruzione di salto setti il program counter oltre la fine di un metodo, causando il crash della JVM. Effettuati con esito positivo questi (e molti altri) controlli, la fase di verification lascia spazio alla preparation. In tale contesto a tutte le variabili di classe vengono assegnati i valori di default, in accordo a quanto riportato in Tabella 1. molto importante ricordare che qualunque variabile di classe passa sempre per il suo valore di default, anche quando il programmatore intende assegnarle un valore proprio, e questo pu richiedere alcune accortezze per evitare situazioni di errore.

catore static), non legate quindi a nessuna istanza di una classe. Infine, per ciascun tipo, la JVM inserisce nei class data della Method Area un constant pool. Esso una sorta di array ordinato contenente tutte le costanti usate dal tipo, inclusi i literals ed i references simbolici ad altri tipi. La descrizione esatta della struttura del constant pool esula dagli scopi di tale articolo, tuttavia esso, o meglio la sua versione a runtime (il runtime constant pool), gioca un ruolo cruciale nel successivo processo di risoluzione. Bench la Method Area non sia direttamente accessibile alle applicazioni Java, qualunque programma in esecuzione vi fa continuamente riferimento [1]. Una volta costruite opportunamente le strutture dati rappresentanti il tipo nella Method Area, la fase di loading prevede infine la creazione di una nuova istanza di java.lang.Class che rappresenta una sorta di ponte di collegamento tra la Method Area ed i programmi Java, consentendo ai programmatori di recuperare ogni sorta di informazione sui tipi caricati al suo interno. Le istanze di tale classe sono infatti alla base del meccanismo di RunTimeTypeIdentification di Java.

La prima fase, quella


di loading, corrisponde allestrazione dei dati binari dal file con estensione .class
Lultimo step della fase di linking la resolution. Si tratta di un processo molto complesso che consiste nella sostituzione di tutti i reference simbolici contenuti nel constant pool con puntatori diretti. La struttura di tali puntatori dipende dalla piattaforma, ma tipicamente consistono in un puntatore nativo ai class data nella Method Area se il reference corrispondente punta a variabili o metodi statici. Reference a variabili o metodi distanza sono invece tipicamente risolti come offset a partire dallinizio dellimmagine delloggetto sullo Heap. Come illustrato in Figura 1, la fase di resolution opzionale, nel senso che la JVM pu liberamente
LISTATO 1
Esempio di initializers multipli

Seconda fase: linking dei tipi


Terminati i passi di loading, la JVM inizia il processo di linking del tipo, che composto da tre sottoprocessi distinti: verification, preparation e resolution (opzionale). La fase di verification corrisponde allanalisi dei dati appena caricati in memoria ed alla verifica della loro correttezza in termini dellobbedienza alla semantica del linguaggio. In realt anche su questo punto le specifiche della JVM lasciano abbastanza libert agli implementatori che potrebbero decidere di anticipare alcuni di questi controlli direttamente al momento del parsing dello stream di dati estratto dal class file. La verification include un numero abbastanza elevato di controlli, tra i quali: la verifica che classi final non siano estese e che metodi final non siano ridefiniti; la verifica che tutte le classi (a parte Object) abbiano una superclasse;

public class Esempio1 { static { echo(Uno); } static String s = echo(Due); static { echo(Tre); } private static String echo(String s) { System.out.print(s + ,); return s; } public static void main(String[] args) { } }

Computer Programming n. 142 - Gennaio 2004

45

linguaggi
LISTATO 2
Inizializzazione di gerarchie di classi

suo primo uso attivo. Solo le seguenti sei attivit sono classificate come uso attivo: creazione di una nuova istanza di una classe; invocazione di un metodo statico di una classe; uso di un field statico non costante dichiarato in una classe o interfaccia; uso di alcuni metodi della reflection API; inizializzazione di una sottoclasse; designazione di una classe come main-class. Si noti come nessunaltra attivit al di fuori di queste sei comporti inizializzazione di un tipo da parte della JVM. Lo scopo ultimo dellinizializzazione lassegnazione del valore proprio alle variabili di classe; a tal fine, Java mette a disposizione del programmatore due strumenti distinti: static variable initializers static initialization block Un semplice esempio duso di tali meccanismi riportato nel Listato 1. In esso sono presenti due static initialization block ed uno static variable initializers, che vengono sempre eseguiti nellordine testuale di dichiarazione. Bench una strategia come quella descritta nel Listato 1, con due static initialization block distinti, possa sembrare strana, essa perfettamente legale, bench non raccomandabile in quanto a chiarezza del codice.

class Super { static { System.out.println(Super inizializzato); } } class Sub extends Super { static { System.out.println(Sub inizializzato); } public static int x = 5; }

class EsempioPadre { static { System.out.println(EsempioPadre inizializzato); } } public class Esempio2 extends EsempioPadre { static { System.out.println(Esempio2 inizializzato); } public static void main(String a[]){ int i = Sub.x; } }

decidere di posporla ad una fase successiva a quella di linking, e pi precisamente al primo utilizzo del reference simbolico stesso. In questo ultimo caso si parla di late resolution, mentre si parla di early resolution quando la JVM decide di risolvere i tipi direttamente nella fase di linking. Lunico obbligo imposto dalle specifiche agli implementatori quello di dare sempre e comunque lidea di star utilizzando late resolution. Questo vuol dire che anche quando la JVM utilizza una strategia di early resolution, essa deve segnalare gli eventuali errori incontrati solo allultimo momento utile, e cio in corrispondenza del primo utilizzo effettivo di ogni reference. Ad esempio la risoluzione di un qualunque reference simbolico ad un field o ad un metodo potrebbe sollevare un NoClassDefFoundError se la classe cui fa riferimento non fosse rintracciabile in base alle impostazioni correnti del classpath. Se tuttavia quello stesso reference non fosse mai utilizzato nel corso dellesecuzione, lerrore non andrebbe mai segnalato e tutto dovrebbe procedere come se la sua risoluzione non avesse mai avuto corso.

La fase di verification
corrisponde allanalisi dei dati appena caricati in memoria ed alla verifica della loro correttezza in termini dellobbedienza alla semantica del linguaggio
Si noti come il metodo main della classe in oggetto sia completamente vuoto, ma laver designato tale classe come main-class corrisponde ad un suo uso attivo e d quindi luogo allinizializzazione. Sia gli static variable initializers che gli static initialization block sono raccolti dalla JVM in un unico ClassInitializationMethod, che viene invocato come ultimo passo della procedura di inizializzazione, come vedremo in seguito in maggior dettaglio. La JVM non costruisce un ClassInitializationMethod per tutte le classi che carica ed inizializza, ma solo per

Inizializzazione di classi
In questa fase, infine, alle variabili di classe viene assegnato il valore proprio, sostituendo il valore di default, in base a quanto specificato dal programmatore. Mentre le specifiche della JVM lasciano molta libert alle implementazioni per quanto riguarda le fasi di verification e linking, esse definiscono invece rigorosamente il momento in cui un tipo deve essere inizializzato. Tale momento coincide inderogabilmente con il

46

Computer Programming n. 142 - Gennaio 2004

PROGRAMMING
quelle che richiedono effettivamente del codice Java per linizializzazione. Si consideri ad esempio il seguente codice:
public class NoClInit{ public static final int x = 10; public static final int y = 20; }

Ad un primo esame tale codice sembra del tutto simile al Listato 1, ma la JVM non crea per la classe NoClInit il ClassInitializationMethod. Il motivo risiede nel fatto che le due variabili in essa dichiarate sono inizializzate a valori costanti noti a compile time. La JVM tratta le costanti in maniera peculiare; infatti esse non vengono memorizzate nella Method Area tra i dati di classe della classe che le dichiara, ma il loro valore viene copiato direttamente nel constant pool delle classi che le utilizzano. Ad esempio una classe come la sottostante, che accede ad una costante dichiarata al suo esterno:
public class UsaCostanti{ static final int a = NoClInit.x; }

loro valore proprio e non a quello di default. Questa strategia implica che la prima classe inizializzata sia sempre e comunque Object. Un esempio di quanto avviene in presenza di gerarchie complesse di classi riportato nel Listato 2. In esso si fa un uso attivo della classe Esempio2, in quanto main class dellapplicazione, che deve pertanto essere inizializzata. Appena terminato il suo linking, la JVM verifica se la superclasse diretta stata a sua volta inizializzata. Poich questo non ancora avvenuto, prima di invocare il ClassInitializationMethod di Esempio2, la JVM effettua linizializzazione di EsempioPadre. Il processo si ripete a tal punto identico, con EsempioPadre nel ruolo di discendente ed Object in quello di antenato (si noti come in nessuna delle implementazioni esistenti della JVM, Object necessiti di un ClassInitializationMethod). Le classi inizializzate immediatamente prima dellesecuzione del metodo main sono dunque le seguenti, ordinate cronologicamente: Object EsempioPadre Esempio2.

Larea di memoria
designata a contenere tutte le informazioni sui tipi Java denominata Method Area
Solo dopo linizializzazione di EsempioPadre, la JVM inizia lesecuzione del bytecode corrispondente al corpo del metodo main. In tale metodo si accede ad un field statico della classe Sub e ci, come ormai sappiamo, un uso attivo di tale classe. Poich per la superclasse diretta di Sub non a quel punto ancora stata inizializzata, la JVM non chiama subito il ClassInitializationMethod di Sub, ma passa dapprima ad inizializzare la classe Super, come si pu facilmente constatare analizzando loutput prodotto dallesecuzione di questa semplice applicazione. molto importante notare come lutilizzo di un field statico sia un uso attivo solo della classe che dichiara quel field. Consideriamo ad esempio il seguente semplice codice:
class Super{ static int a = 10; static {System.out.println(Super initialized);} }

avr il valore 10 memorizzato da qualche parte del suo constant pool ed il ClassInitializationMethod acceder ad esso per inizializzare la variabile a.

Inizializzazione di gerarchie di classi


Quello finora descritto dunque il processo completo di inizializzazione di una singola classe, dal suo caricamento in memoria fino allesecuzione (eventuale) del suo ClassInitializationMethod. In realt lintera procedura lievemente complicata dalla necessit, se non ancora effettuato, di caricare ed inizializzare la superclasse diretta di qualunque classe in fase di initialization. Questo naturalmente allo scopo di garantire che tutte le variabili statiche dichiarate nelle superclassi ed ereditate da una sottoclasse possano essere usate quando gi si trovano al
LISTATO 3
Inizializzazione di interfacce

interface I { int i = Esempio3.getX(5); } interface J extends I { int j = Esempio3.getX(10); } public class Esempio3 { public static int getX(int x){ System.out.println(getX + x); return x; } public static void main (String a[]) { int l = J.j; } }

class Sub extends Super{ static { System.out.println(Sub initialized);} } public class Test { public static void main (String[] args){ int a = Sub.a;

Computer Programming n. 142 - Gennaio 2004

47

linguaggi
LISTATO 4
Possibile implementazione della procedura di inizializzazione

Inizializzazione di interfacce
Quanto detto finora per le classi vale in larga misura anche per le interfacce. In esse non possibile dichiarare degli static initialization block, ma alloccorrenza viene comunque costruito un InterfaceInitializationMethod che la JVM invoca al termine della procedura di inizializzazione. La differenza fondamentale con il processo di inizializzazione delle classi che per le interfacce non avviene linizializzazione delle superinterfacce dirette. Consideriamo ad esempio il Listato 3. In esso siamo ormai immediatamente in grado di individuare il primo uso attivo che viene fatto della classe Esempio3, in quanto main class dellapplicazione. Allo stesso modo laccesso al field j dellinterfaccia J un uso attivo dellinterfaccia stessa. Il punto chiave, e lunica differenza con quanto detto finora per le classi, che linterfaccia I, padre di J, non viene inizializzata in tale frangente. Loutput del programma consiste infatti nella sola linea di testo getX=10, a testimonianza che solo lInterfaceInitializationMethod di J stato eseguito. Si noti inoltre come, sostituendo lunica istruzione del metodo main con la seguente
int i = J.i;

/** Questo codice presentato esclusivamente a fini didattici, allo scopo di illustrare il lavoro svolto dalla JVM allatto di inizializzare una qualsiasi classe o interfaccia. Non esiste nulla di simile nelle Java API. */ public int initialize(InitializingType aType) throws ExceptionInInitializerError { synchronized (aType) { while (aType.getStatus() == InitializingType. INITIALIZATION_IN_PROGRESS){ if (aType.getInitializingThread() == Thread.currentThread()){ return 0; } try{ aType.wait(); }catch(InterruptedException ie) {/*ignore*/} if (aType.getStatus() == InitializingType.FULLY_INITIALIZED ){ return 0; } else if (aType.getStatus() == InitializingType.INITIALIZATION_ERROR ){ throw new NoClassDefFoundError(); } else { aType.setStatus(InitializingType. INITIALIZATION_IN_PROGRESS); aType.setInitialingThread (Thread.currentThread()); } }//while }//synchronized if (aType.isAClass() && aType.getSuperClass(). getStatus() == InitializingType.NOT_INITIALIZED){ initialize(aType.getSuperClass()); } try { if (aType.isAClass() ){ aType.executeClassInitializationMethod(); } else{ aType.executeInterfaceInitializationMethod(); } }catch(Exception ie){ synchronized (aType){ aType.setStatus(InitializingType. INITIALIZATION_ERROR); aType.notifyAll(); } throw new ExceptionInInitializerError (ie); }//catch synchronized (aType){ aType.setStatus(InitializingType. FULLY_INITIALIZED); aType.notifyAll(); } return 0; }//initialize

si ottiene in output: getX=5. Analogamente a quanto detto per la classi, laccesso ad un field statico di uninterfaccia corrisponde ad un uso attivo esclusivamente dellinterfaccia che dichiara il field e non delle eventuali sottointerfacce che ereditano il field stesso.

Dettagli della procedura di inizializzazione


Poich Java un linguaggio intrinsecamente multithreading, linizializzazione di una classe o interfaccia richiede unattenta sincronizzazione. Diversi thread potrebbero infatti richiedere linizializzazione dello stesso tipo allo stesso tempo. La JVM deve inoltre essere in grado di riconoscere ed opportunamente gestire situazioni nelle quali linizializzazione di una classe o interfaccia sia richiesta ricorsivamente dallo stesso thread. Consideriamo ad esempio il seguente codice ove supponiamo che le classi A e B non siano ancora state inizializzate:
public class A{ static int x = B.getX();

} }

Lesecuzione di tale codice comporta linizializzazione solo della classe Super e non di Sub poich, bench si acceda al field a attraverso il nome della sottoclasse, tale field dichiarato nel padre. Si noti come naturalmente anche le classi Test ed Object, alla luce di quanto finora detto, vengano a loro volta inizializzate nel corso dellesecuzione dellapplicazione in esame.

static int rnd(){ return (int)Math.random();} } public class B{ static int getX(){ return A.rnd();} }

Il processo di inizializzazione per la classe A, come abbiamo visto, comporta lesecuzione del suo unico

48

Computer Programming n. 142 - Gennaio 2004

PROGRAMMING
class variable initializer che, a sua volta, richiede linizializzazione della classe B. Lassegnazione del valore proprio alla variabile x comporta infatti linvocazione di un metodo statico definito nella classe B e questo corrisponde anche al primo uso attivo di B. Eseguendo tale metodo, la JVM incorre tuttavia in un nuovo uso attivo della classe A che, pur non essendo ancora stata completamente inizializzata, non tuttavia da considerare da inizializzare ex-novo, ma piuttosto in fase di inizializzazione ad opera dello stesso thread. levando una NoClassDefFoundError, devono essere intraprese due azioni distinte). In primo luogo lo stato del tipo viene impostato al valore INITIALIZING; successivamente il thread corrente si registra al tipo come il thread che sta effettuando linizializazzione stessa, rilasciando infine il lock acquisito. Solo a questo punto inizia il processo di inizializzazione vero e proprio. Se il tipo una classe e la superclasse diretta non stata inizializzata, si invoca ricorsivamente il metodo initialize() sulla sua superclasse diretta, in ossequio alle regole di inizializzazione illustrate in precedenza. Se tale processo va a buon fine, si procede infine allinvocazione del ClassInitializationMethod del tipo, che a sua volta conterr linvocazione dei class variable initializers e degli static block initializers, o dellInterfaceInitializationMethod se il tipo una interfaccia. Se lesecuzione degli initializers completa normalmente, si riacquisisce il lock sul tipo, si imposta il suo stato a FULLY_INITIALIZED e si notificano tutti i thread eventualmente in attesa. In caso di eccezione, invece, dopo aver riottenuto il lock, si imposta lo stato di errore e si notificano i thread in attesa, dopodich si propaga leccezione a segnalare la mancata inizializzazione.

Le specifiche della JVM


lasciano molta libert alle implementazioni per quanto riguarda le fasi di verification e linking
Tutte queste problematiche devono essere tenute in conto nella scrittura della procedura effettiva di inizializzazione, una cui possibile implementazione viene illustrata, esclusivamente a fini di esempio, nel Listato 4. Il codice presentato non fa parte di nessuno dei package delle Java Api, ma solo una descrizione in linguaggio Java dellalgoritmo di inizializzazione eseguito dalla JVM. In esso si assume di avere a disposizione la classe InitializingType, una cui istanza modelli una classe o interfaccia da inizializzare, e che ingloba nel suo stato interno tutte le informazioni necessarie alla procedura di inizializzazione stessa. Il primo passo eseguito dalla JVM la verifica in modo esclusivo dello stato corrente del tipo in fase di inizializzazione (si noti laccesso synchronized al tipo in oggetto che blocca il thread corrente fino a quando un eventuale altro thread che stia inizializzando lo stesso tipo non rilasci il lock su di esso). Se tale tipo risulta gi in fase di inizializzazione possono presentarsi due possibilit: 1) la richiesta di inizializzazione stata effettuata in modo ricorsivo dallo stesso thread; in tal caso la procedura termina immediatamente in modo normale; 2) non si tratta di richiesta ricorsiva; il thread corrente va allora in wait() in attesa di essere notificato dal thread che ha precedentemente avviato linizializzazione del tipo in oggetto. Terminato questo primo blocco, se il tipo non stato completamente inizializzato e se il suo stato non invalido, (circostanze che provocano entrambe luscita immediata dal metodo, in modo normale o sol-

Conclusioni
Abbiamo visto con dovizia di particolari tutto quanto legato al primo uso attivo di una classe o interfaccia, attivit per molti versi banale dal punto di vista della programmazione in Java, ma che si traduce in un processo molto complesso a livello della macchina virtuale. La conoscenza approfondita di questo processo comunque imprescindibile per realizzare programmi Java correttamente funzionanti. Nel prossimo articolo affronteremo nei dettagli un uso attivo particolare tra i sei individuati: listanziazione di un nuovo oggetto sullo heap.

BIBLIOGRAFIA & RIFERIMENTI


[1] G.Anselmi Accesso concorrente a risorse di classe in Java, Computer Programming n. 127, set. 2003 [2] B.Venners Inside the Java virtual machine, II edition [3] B.Eckel Thinking in Java, III edition [4] The Java Language specification http://java.sun.com/docs/books/jls/html/index.hml [5] The Java Virtual Machine Specification http://java.sun.com/docs/books/vmspec/html/VMSpec TOC.doc.html

CODICE ALLEGATO
ftp.infomedia.it
Init1

Computer Programming n. 142 - Gennaio 2004

49