Newsgroup: it.comp.java
Titolo: Concorrenza

Salve a tutti,
ho dei problemi di concorrenza con delle Servlet in Java. Praticamente
quando la servlet viene richiamata per la seconda (o n-esima) volta le
variabili (non static) vengono sovrascritte. Ho risolto (ma qualche volta
non funziona lo stesso e non capisco il perchè) implementando
SingleThreadModel. Ho letto però che il metodo nelle Servlet 2.4 è
deprecato. Quale può essere l'alternativa per il mio problema?
Il mio ambiente è così strutturato :
j2sdk1.4.1_02,
tomcat4.0.6 e
mysql-connector-java-3.0.8-stable-bin.jar
per connettermi a mysql4.0.13
su linux redhat 8.0
Un grazie anticipato a chi mi aiuterà a risolvere il problema!
Marco

Marco wrote:

Quali variabili? Gli attributi della classe servlet?
Se sì è normale, anzi potrebbero essere sovrascritti  anche la seconda 
volta perchè la stessa istanza di una servlet gestisce più richieste.
Con singlethreaded le richieste contemporanee vengono gestita da istanze 
diverse ma non per forza da nuove istanze.
Perciò è normale che avvengano sovrascritture anche se con meno probabilità.
Soluzione:
non devi salvare dati persistenti (tra diverse richieste) in attributi 
della classe servlet anche se non statici.
Considera l'uso delle sessioni se hai questa esigenza.
Ho risposto un pò di fretta ma spero di essere stato abbastanza chiaro.
Ciao Luca
 

dipende da cosa devi fare


Ciao Marco

sessione
Sì l'assudità è proprio lo stesso ID di sessione.
La probabilità di averli uguali è estremamente piccola (la stringa 
identificativa dell'ID è molto lunga) anche se non impossibile.
Sembrerebbe un baco molto grave di quella versione di tomcat ma non ne 
avevo sentito parlare.
Sei in un ambiente con bilancio di carico?
Usi apache con tomcat? 
Ci fai vedere il codice in cui usi le sessioni?

 Ci fai vedere il codice in cui usi le sessioni?
Ho fatto anche una classe di prova. Prova a collegarti con due ip diversi e
guarda cosa succede Eccola :
package jsb_demo;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import jsb_library.*;
public class provami extends HttpServlet
{
  private provami_var me;
  //  private dbase db;
 public void init(ServletConfig config) throws ServletException
 {
  super.init(config);
 }
////////////////////////////////////////////////////////////////////////////
 public boolean init_servlet(HttpServletRequest request,HttpServletResponse
response)  throws ServletException, IOException
 {
    me=new provami_var();
   response.setContentType("text/html");
   me.out = new PrintWriter (response.getOutputStream());
   me.session=request.getSession( true );
   if (me.session==null) {return false ;}
   return true;
 }
 //////////////////////////////////////////////////////////////////////////
 public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
 {
    init_servlet(request,response);
    System.out.println("::before_SESSION_ID:"+me.session.getId()+"
Provenienza:"+request.getRemoteAddr());
    me.salvo1=request.getParameter("str");
    me.salvo2=Integer.parseInt(request.getParameter("int"));
    System.out.println("::Before_VALORI_SERVLET:"+me.salvo1+" -- 
"+me.salvo2);
    try{
      Thread.sleep((long)30000);
    }catch(Exception e){e.printStackTrace(); }
    System.out.println("::after_VALORI_SERVLET:"+me.salvo1+" -- 
"+me.salvo2);
    System.out.println("::after_SESSION_ID:"+me.session.getId()+"
Provenienza:"+request.getRemoteAddr());
    //response.sendRedirect("jsb_demo.provami");
    put_html(request);
 }
////////////////////////////////////////////////////////////////////////////
////
 public void put_html(HttpServletRequest request) throws ServletException,
IOException
 {
    me.out.println("<br>::after_VALORI_SERVLET:"+me.salvo1+" -- 
"+me.salvo2);
    me.out.println("<br>::after_SESSION_ID:"+me.session.getId()+"
Provenienza:"+request.getRemoteAddr());
    me.out.close();
/*
    try{
      out.println("PROVAMI SERVLET: servlet di prova...");
      db = new dbase();
      db.connect("jdbc:mysql://2rmc/jsb","root","");
      db.setquery("select * from struttura");
      db.read();
      while(db.next()){out.println(db.getString("nome_oggetto")+"<br>");}
      out.close();
    }catch(Exception ex){ex.printStackTrace();}
*/
  }
}
class provami_var
{
  public PrintWriter out;
 public HttpSession session;
  public String salvo1;
  public int salvo2;
}

Si era detto che non devi usare variabili di classe.
Non usare "provami_var".
Per avere la sessione chiedi semplicemente "getSession" nei metodi doGet o 
doPost.
Idem per il printWriter.
L'errore è solo tuo, non di tomcat.
Per forza le variabili si sorascrivono e per forza hai la stessa sessione:
la salvi in una variabile dell'oggetto di tipo servlet e la richiami da lì.
Ciao

Ho notato la discussione, mi ha incuriosito il problema delle
variabili di classi... anch'io ho avuto lo stesso problema, usando
variabili di classe, ma onestamente, non ho voluto toglierle se no
sarebbe stato un casino esagerato toglierle da tutte quelle servlet,
però ho usato il singleThreadModel sulle servlet interessate, mi è
sembrato funzionare. L'ambiente che uso è lo stesso di Marco che ha
postato il primo messaggio.
Ora, comunque provo a non usare variabili di classe in qualche servlet
e vedo se cambia qualcosa - però mi sembra strano che la cosa sia così
drastica. Le variabili di classe sono condivise e quelle dei metodi
no?
ciao a tutti.

redpill wrote:

La questione è molto semplice:
una stessa istanza di sevlet gestisce più richieste browser, anche di 
sessioni diverse.
Se si impostano attributi di un oggetto condiviso è giusto che questi 
attributi siano visibili a più "browser".
Sono state inventate appunto le sessioni per salvare dei dati relativi ad 
un singolo utente/browser lato server.
L'uso del siglethreaded a questo scopo oltre che peggiorare drasticamente 
le prestazioni dell'applicazione web è proprio sbagliato.
Come avevo già detto riduce semplicemente la probabilità di sovrascrittura 
di variabili condivise (non può succedere con richieste contempoanee).
A questo  punto si potrebbe chiedere a che cosa serva l'interfaccia 
SingleThreaded. La risposta è per sincronizzare l'accesso contemporaneo
a risorse condivise per esempio record di database. Tuttavia un buon 
progetto non ha assolutamente bisogno di quell'interfaccia. Consiglio 
vivamente di non utilizzarla.

 vivamente di non utilizzarla.
L'interfaccia SingleThreadModel è un errore di design. E' stata 
considerata per anni una bad-practice, ed ora è stata ufficialmente 
deprecata
Non ha nessun senso (non risolve alcun problema di concorrenza) e non va 
dunque usata: chi lo fa non si lamenti poi con java, con tomcat, con sun 
o con chiunque altro ;)
uL

 la salvi in una variabile dell'oggetto di tipo servlet e la richiami da
lì.
Ti ringrazio vivamente per l'aiuto che mi hai dato. Sei stato veramente
molto gentile.
Marco.

 Quale puň essere l'alternativa per il mio problema?
Se ho capito bene,il tuo problema č fornire alla servlet uno STATO, ossia
memorizzare dei valori a livello di sessione.
In tal caso devi riferirti al Context -> Session , e li memorizzare tali
variabili.
Se poi tali variabili devono essere condivise da piů sessioni utente devi
inserirle nel Context -> Application. Cosi facendo tutte
le istanze e Servlet condivideranno le stesse variabili.
Ciao

>Se ho capito bene,il tuo problema è fornire alla servlet uno STATO,
Se ho capito bene,il tuo problema è fornire uno STATO alla SESSIONE
Sorry! ;o)