2013-01-09 8 views
19

Ho bisogno di scrivere un bean che agisca da contatore di quante volte è stato effettuato l'accesso.JEE6 @Application Bean e concorrentopropato

Sto pensando di utilizzare @ApplicationScoped fagioli con AtomicInteger come quella

@ApplicationScoped 
class VisitsCounter { 

    private AtomicInteger counter; 

    @PostConstruct 
    public void construct() { 
     counter = new AtomicInteger(0); 
    } 

    public int visited() { 
     return counter.incrementAndGet(); 
    } 
} 

La mia domanda è: è ok quando si considera più richieste allo stesso tempo? O devo giocare con le annotazioni @ConcurrencyManagement e @Lock? Suppongo che lo Atomic* debba fare il trucco ma non ne sono sicuro.

Lo stesso vale anche quando si dispone di raccolte thread safe come campi? Per esempio. dire che ho

@ApplicationScoped 
class ValuesHolder { 

    private List<String> values; 

    @PostConstruct 
    public void construct() { 
     values = Collections.synchronizedList(new LinkedList<String>()); 
    } 

    public void insert(String value) { 
     values.add(value); 
    } 

    public String remove(String value) { 
     return values.remove(value); 
    } 
} 

sono le operazioni davvero thread-safe?

Si dice che le annotazioni e le serrature di concorrenza debbano essere utilizzate in caso di modifica dello stato del bean, ma cosa succede se la mia lista si occupa già della sicurezza dei thread?

+2

Come implementato, non vedo alcun problema di concorrenza. – McDowell

risposta

31

In CDI non si dispone di gestione della concorrenza, in modo da @ApplicationScoped afferma semplicemente la cardinalità dell'oggetto iniettato (cioè indica al motore a iniezione per creare una sola istanza di bean e usarlo in tutti l'applicazione). Non trasforma il bean in un EJB e non impone alcun vincolo di concorrenza.

Quindi, mentre le operazioni negli esempi sono intrinsecamente thread-safe, grazie allo AtomicInteger e all'elenco sincronizzato, lo stesso non è vero in generale.

In generale, è possibile:

  • sincronizzare manualmente l'elenco accessi attraverso le primitive di concorrenza normali (come hai fatto)

  • o utilizzare il javax.ejb.Singleton annotazione, che indica al server applicazioni gestire la concorrenza. Questo trasforma il bean in un EJB e applica per impostazione predefinita @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) e @Lock(LockType.WRITE).

A proposito, @ConcurrencyManagement e @Lock sono disponibili solo su bean di sessione Singleton.

+0

Buono. Stavo pensando cosa sarebbe successo se avessi iniettato un bean '@ ApplicationScoped' in un bean' @ Stateful', sembra che tu possa incorrere in problemi, dal momento che da 2 istanze dell'EJB puoi modificare gli stessi dati. – dalvarezmartinez1