[Java] Servlet werkt alleen goed als entrypoint synchronized

Pagina: 1
Acties:

  • Norjee
  • Registratie: April 2000
  • Niet online
Hmm vage titel.. maar dr past niet meer in..

Maar ok mijn probleem:

Mijn (nieuwe) website is een servlet.. heel fijn werkt ook wel lekker.. maar resin (servlet runner) loopt vast wanneer het entrypoint niet synchronized is.. het werkt even.. en na een paar minuten gebeurd wordt het traag en wordt resin automatisch geherstart.. Op mn eigen pc werkt het wel prima.. maar daar ben ik ook de enige bezoeker.. dat is dus geen kunst ;)

Ik gebruik webmacro als template engine..

Hier de simpele code van mijn servlet:
PHP:
1
2
3
4
5
6
public class ConceptQ extends WMServlet 
    {   
    public synchronized Template handle(WebContext context) throws HandlerException
        {           
        }   
    }


handle is dus het entrypoint..

in handle gebeurd een heleboel.. onder andere worden objecten in de context geplaatst:
deze context bestaat alleen voor 1 request, hier kan dus niks mis gaan.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
String act = context.getForm("act");
                
            if (act.equalsIgnoreCase("meldaan"))
                {
                context.put("CQ_aanmeld" , (new CQ_aanmeld(context)));      
                }
            else if (act.equalsIgnoreCase("login"))
                {
                context.put("CQ_login" , (new CQ_login(context)));      
                }   
            else if (act.equalsIgnoreCase("loguit"))
                {
                context.put("CQ_loguit" , (new CQ_loguit(context)));        
                }       
            else if (act.equalsIgnoreCase("show"))
                {
                context.put("CQ_show" , (new CQ_show(context)));        
                }


Sommige van deze objecten gebruiken weer andere objecten die data lezen en schrijven..

bijv CQ_show gebruikt CQ_verhaal (linkjes)


CQ verhaal is dus per definitie niet threadsafe.. het heeft een statische hashtable die instances van CQ_verhaal bevat (dit dat zodat een CQ_verhaal object niet elke keer alle db queries hoeft te herhalen) en leest files.. en twee keer tegelijk dezelfde file lezen is ook geen goed plan..
Nu heb ik getInstance keurig synchronized gemaakt, en getText ook.. dus voor zover ik het kan begrijpen moet dit nu gewoon wel threadsafe zijn...

Ik snap dus ook niet dat de server in de soep loopt wanneer ik het main entry point, handle, dus niet synchronized maak.. want alle functies die enge dingen doen heb ik al synchronized.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Volgens mij zit het probleem in het feit dat je dus geen algehele lock op je resources hebt. Stel dat je net de 1e ifstatement conditie succesvol hebt getest. Dan zou het kunnen voorkomen dat er een 2e thread aankomt die die ifstatement ook wilt doen. Aangezien de 1e thread 'context.put("CQ_aanmeld" , (new CQ_aanmeld(context)));' nog niet heeft uitgevoerd zal voor de 2e thread ook de conditie slagen. Nu kunnen ze beiden dus 'context.put("CQ_aanmeld" , (new CQ_aanmeld(context)));' uitvoeren.


Je moet dus een lock krijgen op context.
code:
1
2
3
synchronized(context){
    ...code
}


Verder weer ik eerlijk gezegd geen antwoord op je probleem, want ik ben niet thuis in jsp.

[edit]
Waarom haal je iedere keer die form op??

  • Norjee
  • Registratie: April 2000
  • Niet online
Je hebt gelijk over die context.getForm("act") :) kheb het veranderd

die context is elke keer een nieuwe context, elke thread heeft zijn eigen context (okee dit weet ik niet zeker.. maar dat lijkt me erg logish.. aangezien met die context de html opgebouwd wordt, en het wel fijn is is elke request een andere context voorgeschoteld krijgt)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Schijnbaar worden er toch door meerdere threads tegelijk een handle uitgevoerd anders zou dit probleem niet gefixed zijn met een synchronized.

  • Norjee
  • Registratie: April 2000
  • Niet online
Das waar...

maar die meerdere threads zouden volgens mij tegelijk die handle moeten kunnen uitvoeren omdat alle objecten die door de handle in een context geplaats worden al gesynchronized zijn, dus dan snap ik niet waarom die handle gesynchronized moet worden..

Maar ik zal wel iets over het hoofd zien..

Ik heb nu die handle niet synchronized, en een tweede handle wel..
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ConceptQ extends WMServlet  
    {     
    public Template handle(WebContext context) throws HandlerException 
        {
         /// code
        return handleSyn(context);
        } 

 public synchronized Template handleSync(WebContext context) throws HandlerException 
        {
        /// ook code           
        }       
    }


Ben begonnen met alle code in handleSync te zetten en zet stukje bij beetje meer code in handle.. kzie dan wel waar het fout gaat.. tis een beetje een knullige manier om te testen, maar ik weet ook geen betere manier :))

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Ik vind concurrency zelf ook vrij lastig en waar ik me altijd aan stoor is dat iedereen iets met threads doet terwijl ze er niet veel van begrijpen en dan bedoel ik vooral de gevaren die threads met zich meebrengen. Ik raad je echt aan om een goed boek ofzo erover te kopen.

En dan is dit een aanrader:
Concurrent Programming in Java(TM): Design Principles and Pattern (2nd Edition)

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 17-08 22:44
Vraagje... De basis servlet die je geschreven hebt, heeft die toevallig public of private velden die op meerdere plaatsen in de servlet gebruikt wordt?

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 17-08 22:44
Het lijkt erop dat je verkeerd aan het redeneren bent. Vraag jezelf niet af WAT je moet synchronizen, maar WAAROM je moet synchronizen. Over het algemeen moet je geen synchronized statements gebruiken in een servlet. Het geeft vaak een fout of slecht ontwerp aan.

Onthou goed dat een servlet door meerdere threads tegelijkertijd gerunt kan worden. Standaard is er van een Servlet ook maar 1 enkele instantie. Zelfs als meerdere gebruikers op dezelfde webcontainer requests uitvoeren. Let hier ook goed op bij het ontwikkelen van een servlet. Pas op met instance variabelen, pas ook op met variabelen die zichtbaar zijn op een hoger niveau dan de sessie die je op dat moment aan het afhandelen bent.

  • Norjee
  • Registratie: April 2000
  • Niet online
De basis servlet heeft geen public of private velden...

Maar de servlet gebruikt wel files.. en de io naar zo'n file moet gesynchronized worden lijkt mij, omdat er tegelijk meerdere request worden uitgevoerd.. en die dan ook dezelfde file nodig kunnen hebben..

Het andere wat gesynchronized moet worden zijn de CQ_verhaal en CQ_user classes deze zijn een soort singleton met een private static hashtable waar instances inzitten.. de getInstance van deze classes heb ik dan ook gesynchronized.. En zodra deze classes data gaan veranderen zijn ze ook gesynchronized

En tja.. ik zie niet meer wat ik WAAROM moet synchronizen.. dus zie ik maar wat ik moet synchronizen zodat het goed gaat...

Ik ben nu trouwens ook van mn host gekicked met mn goede gedrag..

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 17-08 22:44
Ah, kijk dat maakt een hoop duidelijk. Ik had tot nu toe gemist dat het om een file ging.

Iig: 't Is inderdaad slim om er een Singleton voor te zetten. Wat betreft IO heb ik niet zo veel ervaring met Servlets.

Ik vind het sowieso een vreemde combinatie. Volgens de J2EE specificaties mag je NIET zelf IO doen. Net als synchronized blokken. J2EE gaat er van uit dat data opslag in een database gebeurd. Servlets zijn onderdeel van de J2EE spcificatie. Niet zo vreemd dat je er flink ruzie mee hebt.

Technisch zal het moeten kunnen, maar of het echt praktisch is, geen idee.

Indien mogelijk zou ik voor een database gaan.

  • Norjee
  • Registratie: April 2000
  • Niet online
Update:

Nadat ik van mn host gekicked ben heb ik maar besloten een eigen server te gebruiken.. dit werkt nu perfect.. ik gebruik nu ook mysql voor de grote textfiles.. er wordt een keer een file geladen.. en als deze nog niet in de db staat wordt deze in deze database gezet, en wanneer een file in de db staat wordt hij niet als file geladen..
Maar omdat ik toch wou weten of het nu aan die files lag.. heb ik even getest met alleen files, en ook dit gaat gewoon goed voor een uur, dus ik denk niet dat dat het probleem geweest is.

Trouwens de reden dat ik files gebruik is dat het voor mij een stuk makkelijker is om een kleine database te backuppen dan een grote.. ik heb maar een simpele modem verbinding met internet en elke keer als backup een 20mb (ok eigenlijk niks) database te downloaden is ook niet echt leuk.. en een file downloaden is makkelijker dan 1 database entry :) Zonder deze grote files is de db maar 1.5MB..

En bedankt voor de hulp :) ik was er al zo'n beetje van overtuigd dat ik alles fout gedaan had en het gewoon niet kon werken, maar dat was dus niet zo :)

  • bille
  • Registratie: Mei 2000
  • Laatst online: 05-08 23:45

bille

Don't call me Buff

Het andere wat gesynchronized moet worden zijn de CQ_verhaal en CQ_user classes deze zijn een soort singleton met een private static hashtable waar instances inzitten..
Hoezo zou je een static hashtable gebruiken als je een singleton maakt? Een singleton is altijd een instantie... dus waarom dan een static hashtable? Je kan ook in de constructor van de class een hashtable zetten en die hoeft dan niet static te zijn nadat de class is geinstantieerd.

De getInstance() methode van je singletons wil je synchronizen om de volgende reden:

stel:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Bla {
    private static Bla myBla;

    //private constructor
    private Bla(){
    }

    public static Bla getInstance(){
        if(myBla==null) {
            myBla = new Bla();
        }
        return myBla;
    }
}


Het bovenstaande wil je niet omdat wanneer je twee threads hebt draaien die beide tegelijk getInstance() aanroepen beide een nieuwe Bla aanmaken (want myBla was nog null) en zodoende heb je dus twee myBla's. De enige correcte manier om het goed uit te voeren is alsvolgt:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Bla {
    private static Bla myBla;

    //private constructor
    private Bla(){
    }

    public static synchronized Bla getInstance(){
        if(myBla==null) {
            myBla = new Bla();
        }
        return myBla;
    }
}



Het is jammer dat het niet anders kan want synchronized is een vrij dure operatie om te doen. Gebruik het dus ook niet op alles wat los en vast zit. Een file wil je inderdaad synchronized toegankelijk maken voor threads. Dat zou je kunnen doen door de IOstream een singleton te maken. Op die manier heb je altijd maar 1 stream op de file waar je naar wilt schrijven. Voor het lezen van een file heb je naar mijn weten geen locking nodig omdat de file in princiepe altijd hetzelfde blijft zolang je er niet naar schrijft en zodoende kan je in dat geval wel met meerdere streams de file inlezen.

Ultra Pilammo 6666Mhz AMD, 4251Mbit/s RAM, Gefors V6666 MegaTurbo, 43" TFS, Ultra 80Gig Firewire netwerkkaart en 5D geluid met 66 speakers in 5 dimensies


  • bille
  • Registratie: Mei 2000
  • Laatst online: 05-08 23:45

bille

Don't call me Buff

Hoe synchronized werkt:
In de JVM wordt voor iedere thread een "monitor" aangemaakt. Een soort .. ehm.. monitor die weet in welk stuk van de code de thread zich bevindt. Op het moment dat een stuk code synchronized is dan zet de monitor zeg maar een hek om dat stuk code heen, net zolang als dat de thread nodig heeft om dat stuk code af te lopen. Als de thread klaar is dan wordt het hek weggehaald en kan de volgende thread dat stuk van de code afzetten en gaan doorlopen.

als je er het fijna van wilt weten:
http://java.sun.com/docs/...tml/memory.doc.html#30206

[ Voor 0% gewijzigd door bille op 02-09-2002 21:28 . Reden: foutje ]

Ultra Pilammo 6666Mhz AMD, 4251Mbit/s RAM, Gefors V6666 MegaTurbo, 43" TFS, Ultra 80Gig Firewire netwerkkaart en 5D geluid met 66 speakers in 5 dimensies

Pagina: 1