2009-03-05 13 views

risposta

34

No, non sono thread-safe, secondo IBM - Java theory and practice: Are all stateful Web applications broken?. Devi sincronizzare.

How HttpSession is not thread safe da Java Ranch potrebbe essere utile.

+3

Leggere i collegamenti! ++ – cherouvim

+0

Perché desideri sincronizzarli? C'è una sessione per client e i client sono single thread non lo è? – OscarRyz

+1

@Oscar Reyes: un client può emettere molte richieste simultanee. per esempio CTRL + CLICK (su Firefox) come un matto sul logo StackOverflow. – cherouvim

4

No. E dal momento che non si desidera che lo stesso cliente (con sessione) di fare richieste simultanee, si dovrebbe serializzare queste richieste come il AbstractController fa in Spring MVC

+1

Mi è piaciuto l'esempio, ma ancora un po 'confuso su come lo userei per la mia applicazione. –

2

In un certo senso, questo dipende dalla vostra progettazione del cliente.

Avete la possibilità, nel vostro web design, per un singolo cliente di avere più richieste simultanee in sospeso utilizzando la stessa sessione HTTP? Questo sembra difficile da fare se non si lega una singola sessione HTTP a più socket. (aka, AJAX) In breve, l'accesso HTTP di un determinato client sarà a thread singolo per quanto riguarda il server, il che significa che una singola sessione è effettivamente thread safe.

La sincronizzazione degli oggetti di sessione renderà l'applicazione più sicura rispetto alle modifiche future che rendono la tua applicazione Web capace di avere più richieste simultanee, quindi non è una cattiva idea. Nelle moderne implementazioni Java, la sincronizzazione non ha il grande costo che era precedentemente associato ad esso, specialmente quando la sincronizzazione di solito non era contenuta. Se la tua applicazione utilizza AJAX, il che implica che ti aspettano più richieste simultanee in volo sul tuo server web, allora la sincronizzazione è un must.

+0

Stavo solo pensando di disabilitare "synchronizeOnSession" per richieste ajax per velocizzare le cose (le richieste ajax sono in esecuzione una dopo l'altra, non in parallelo). Quindi è un grande no no allora? Ho pensato che fosse sicuro per ajax perché il flusso di lavoro è generalmente controllato su javascript. – serg

0

La sessione non è thread-safe e il metodo get non è impostato come sicuro. In generale in un contenitore di servlet si dovrebbe assumere di essere in un ambiente multi-thread e nessun tool fornito è sicuro.

Questo vale anche per gli oggetti memorizzati nella sessione. La sessione stessa non manipolerà l'oggetto memorizzato ma puoi recuperare l'oggetto in thread diversi e tentare di manipolarlo. Spetta a te esaminare il tuo codice per vedere se le condizioni di gara sono possibili.

L'esempio di codice pubblicato è valido, ma il problema potrebbe esistere oltre lo scopo limitato del tuo esempio. Assicura che non ci siano condizioni durante l'impostazione della sessione, ma non c'è nulla che impedisca ad un altro thread di sovrascrivere il set. Se il codice nella richiesta dipende dal valore che rimane invariato, potresti comunque essere nei guai.

61

Servlet 2.5 spec:

più servlet esecuzione richiesta discussioni possono avere accesso attivo allo stesso oggetto sessione di allo stesso tempo. Il contenitore deve garantire che la manipolazione dei dati interni delle strutture interne strutture che rappresentano gli attributi della sessione venga eseguita in modo threadthread-safe. Lo sviluppatore ha il la responsabilità per il threadsafe accesso agli oggetti attributo .Ciò proteggerà la collezione di attributi all'interno dell'oggetto HttpSession dall'accesso simultaneo , eliminando l'opportunità per un'applicazione che causa la corruzione della raccolta .

Questo è sicuro:

// guaranteed by the spec to be safe 
request.getSession().setAttribute("foo", 1); 

Questo è non sicura:

HttpSession session = request.getSession(); 
Integer n = (Integer) session.getAttribute("foo"); 
// not thread safe 
// another thread might be have got stale value between get and set 
session.setAttribute("foo", (n == null) ? 1 : n + 1); 

Questo è non garantita per essere al sicuro:

// no guarantee that same instance will be returned, 
// nor that session will lock on "this" 
HttpSession session = request.getSession(); 
synchronized (session) { 
    Integer n = (Integer) session.getAttribute("foo"); 
    session.setAttribute("foo", (n == null) ? 1 : n + 1); 
} 

Ho visto questo ultimo approccio sostenuto (incluso nei libri J2EE), ma non è garantito che funzioni secondo le specifiche Servlet. Si potrebbe use the session ID to create a mutex, ma ci deve essere un approccio migliore.

+0

Cercando di capire cosa "Il contenitore deve garantire che la manipolazione delle strutture di dati interne che rappresentano gli attributi di sessione sia eseguita in modo thread-safe" significa. Non significa che un contenitore come 'tomcat' dovrebbe assicurarsi che i metodi getAttribute e setAttribute siano thread-safe? Inoltre, perché l'ultimo approccio non è garantito per funzionare? – letronje

+0

@letronje - questo significa che le singole chiamate a getAttribute/setAttribute devono essere a prova di thread, ma non vengono fornite garanzie transazionali per il servlet. Quindi, l'uso simultaneo della stessa sessione può comportare uno stato incoerente a meno che lo sviluppatore della servlet non protegga da quello. – McDowell

+1

@letronje - l'ultimo approccio richiede che la sessione si sincronizzi su 'this'. Cioè, ha una firma come 'public syncrhonized void setAttribute ...' o '... setAttribute (String s, Object o) {synchronized (this) ...'. Le specifiche non richiedono questo. Alcuni contenitori servlet fanno questo, ma non ci sono garanzie - il modo in cui il contenitore protegge lo stato interno è un dettaglio di implementazione. – McDowell

1

Non lo sono, ma la maggior parte delle volte, i tuoi clienti potranno accedervi solo con un singolo thread.

Diversi client avranno thread diversi e ognuno avrà una propria sessione.

Come sottolinea Eddie, una situazione in cui è possibile riscontrare due thread che accedono alla stessa sessione è che due chiamate Ajax stanno tentando di modificare lo stesso attributo di sessione. Altrimenti non avrai problemi.