2012-04-11 1 views
1

Gebäude Ich habe eine @ApplicationScoped Bohne für alle Benutzer, die die IDS-> Namen & vice versa in Trove & java.util Karten speichert.Thready Sicherheit von Karten verwendet privat Innenanwendung scoped bean & nur für Zwecke bereit, nachdem sie einmal

Ich baue die Karten nur einmal bei der Konstruktion von Bean oder (im Falle einer manuellen Aktualisierung durch den Website-Administrator).

Innerhalb der Bean-Methoden verwende ich nur die get() mit den Karten, also nicht die Karte zu ändern. Wird dies threadsicher sein, da es nur für fertige Zwecke verwendet wird? Ich teile die Karten nicht mit anderen Beans außerhalb von &, ohne die Karten zu ändern (Hinzufügen/Entfernen von Einträgen), jederzeit in meinem Code.

Ist es in diesem Fall auch notwendig, die Felder endgültig zu machen?

Code Bean wie folgt:

@ApplicationScoped 
@ManagedBean(name="directory", eager=true) 
public class directory { 

    private static TIntObjectHashMap<String> idsToNamesMap; 
    private static TreeMap<String, Integer> namesToIdsMap; 

    @PostConstruct 
    public void buildDirectory(){ 
     // building directory here .... 
    } 

    public String getName(int topicId){ 
     return idsToNamesMap.get(topicId); 
    }  

    public List<Entry<String, Integer>> searchTopicsByName(String query){ 
     return new ArrayList(namesToIdsMap.subMap(query, true, query+"z", true).entrySet()); 
    }   
} 

+1

Ja, Da Sie nicht die Werte modifizieren in die Karten, wird es dir gut gehen. –

+2

Wenn er den Inhalt der Karten nicht ändert, sollten die Karten leer und ziemlich nutzlos sein. Sicherlich bevölkert er die Karten. Und wenn er es ist, muss er die Sichtbarkeit des Gedächtnisses berücksichtigen. Nur weil etwas in einem Konstruktor ausgeführt wird, heißt das nicht, dass es nicht als Schreibzugriff auf die Sammlung gilt.Ich sage nicht, dass es ein Problem gibt, nur darauf hinweisend, dass es nicht so einfach ist wie "später im Hauptprogramm ändere ich sie nie!" Der Anfang des Programms zählt auch. –

+0

ja auf jeden Fall bin ich bevölkern die Karten aber ich glaube, es ist nur ein einzelner Thread, der gerade einmal so tun, wenn die Bohne gebaut wird (da 'buildDirectory' mit Anmerkungen versehen ist' @ PostConstruct') –

Antwort

3

Sie müssen sie in diesem Fall nicht als flüchtig deklarieren oder mit irgendeiner Art von Synchronisation schützen. Solange der Konstruktierungs-Thread sie erstellt und mit dem Hauptspeicher synchronisiert.

Dafür muss der Konstruktier-Thread nur einen einzigen Schreibzugriff auf eine flüchtige Variable ausführen oder eine Synchronisationssperre eingeben/beenden. Dies wird eine Speicherbarriere passieren und alle lokalen Thread-Daten werden im Haupt-Thread sein. Dann ist es für alle anderen Threads sicher, diese Daten zu lesen.

Noch mehr - unnötiger flüchtiger oder Synchronisationsblock - kostet eine schweren Leistungseinbußen - bei jedem Zugriff auf die Variable wird es die Speicher-Schranke passieren - was eine teure Operation ist

+0

Könnten Sie bitte etwas ausführlicher beschreiben, wie Sie dies, wenn möglich, durch ein einfaches Beispiel erreichen können? –

+1

Zum Beispiel Spring Framework und J2EE-Container tun das schon. Wenn Sie ein mit Anmerkungen versehenes Feld deklarieren, müssen Sie sich keine Gedanken darüber machen. Aber wenn Sie sicher sein wollen, können Sie am Ende der @ PostConstruct-Methode einfach synchronisierte (this) {} hinzufügen, um alle lokalen Variablen in den Hauptspeicher zu leeren. (Ich glaube nicht, dass du das tun musst). –

+0

also, wie du sagst, ist alles in Ordnung in meinem Code & ich brauche nichts zu tun!? Machen Sie die Kartenfelder nicht einmal "flüchtig"? –

3

Es könnte eine Sichtbarkeit Problem sein, nachdem das Objekt aufgebaut ist. Das heißt, unmittelbar nach Ihren Konstruktoraufrufen erscheinen die Maps möglicherweise für den Thread, der sie gefüllt hat, aber nicht unbedingt für andere Threads, zumindest nicht sofort. Diese Art von Problem wird ausführlich in Kapitel 3 von Java Concurrency in Practice diskutiert. Ich denke jedoch, dass, wenn Sie die Karten als volatile erklären:

private static volatile TIntObjectHashMap<String> idsToNamesMap; 
private static volatile TreeMap<String, Integer> namesToIdsMap; 

Sie OK sein sollte.

aktualisieren

ich gerade etwas realisiert, während wieder auf den Code suchen. Die Karten sind static - warum werden sie in einem Instanzkontext von einem Konstruktor gefüllt? Zunächst einmal ist es für den Leser verwirrend. Zweitens, wenn mehr als eine Instanz des Objekts erstellt wird, haben Sie zusätzliche Schreibvorgänge in den Maps, nicht nur einen, möglicherweise während andere Threads sie lesen.

Sie sollten sie entweder nicht static machen, oder sie in einem static initialization block auffüllen.

+1

Danke sparc_spread! Ja das macht Sinn. Eigentlich habe ich sie nur statisch gemacht, um auf sie über statische Methoden zuzugreifen, aber ich würde eher in statischen Blöcken statt in statischen Blöcken anfangen, sie stattdessen nicht-statisch zu machen, da die Bean bereits Anwendungsbereich ist und nur eine Instanz für die gesamte Anwendung ist Statisch bringt es sowieso keinen Mehrwert. –

+1

@user Wenn Sie sie in einem Klasseninitialisierer ("statischer" Block) initialisiert haben, würden alle Threadsichtbarkeitsprobleme automatisch behandelt (da es eine Speicherbarriere um die Klasseninitialisierung gibt). Sie können auf diese statischen Strukturen weiterhin von Instanzmethoden aus zugreifen, da dies in einem Bean-Kontext sinnvoller ist. – erickson

+0

@erickson: Danke für den Kommentar! Also, wenn ich die Karten der Bohne (von DB) innerhalb der statischen Block bevölker, dann muss ich nicht die Felder flüchtig machen oder irgendwelche anderen Änderungen vornehmen? –