11. januar 2004 - 05:10Der er
11 kommentarer og 1 løsning
java.lang.IllegalMonitorStateException
Først hvordan det virker, eller skulle virke :)
Client laver en Job objekt og smider det ind i en workpool. Nogle Workers henter Jobs fra WorkPool. Når en worker henter et job, kalder den en funktion på Job der udfører noget, og sætter isFinished til true.
Efter at Klienten har smidt jobbet i workpool, laver den en getResult() på jobbet.
Derfor wait()´er jobbet til isFinished er true.
Fra Job public synchronized Object getResult() { while (!isFinished) { try { wait(); } catch (InterruptedException re) { //dont care, while loop will check if we are done } } return result; }
Fra Worker while (true) { //Look for work SQLJob work = workpool.getWork(); //will sleep here till theres work todo. //do work work.run(sql); System.out.println ("Worker "+id+" finished job "+job); job++; }
Fra workpool public synchronized void addWork(SQLJob job) { queue.enQueue(job); this.notifyAll(); }
public synchronized SQLJob getWork() { while (queue.isEmpty()) { try { wait(); } catch (InterruptedException re) { //Work arrived, see it we gets it } } SQLJob job = (SQLJob)queue.deQueue(); return job; }
Fejlen. java.lang.IllegalMonitorStateException: current thread not owner at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:429) at Job.getResult(Job.java:22) at Client.handle(Client.java:279) at Client.run(Client.java:38) at java.lang.Thread.run(Thread.java:534)
Client og Worker er threads.
Jeg har overvejet at bruge join, men jeg skal jo ikke vente på en thread dør, men blot på et objekt ændre status.
Manuelle og semi-automatiske strategier for identitetsstyring virker - lige indtil nogen beder om dokumentation. For at undgå denne fare har DKTV taget kontrol over sin identitets- og adgangsstrategi.
Det virker temmelig underligt. IllegalMonitorStateException smides sædvanligvis som følge af manglende synkronisering ved brug af wait eller notify, og i dette tilfælde er metoden synkroniseret på this, som wait kaldes på. Det ser ud som om den brokker sig over, er at der mangler synkronisering ved kald af wait, men det gør der ikke...
En løsning kunne måske være at kigge lidt på alternative og måske mere afprøvede design-mønstre; det virker umiddelbart underligt at jobbet har behov for en status der indikerer at jobbet er færdiggjort, men nu kender jeg heller ikke systemets dybere virkemåde.
Selv har jeg arbejdet meget med servere og førhen anvendt pool-mønstre (designmåden kan varieres). Efterhånden er jeg så småt gået væk fra at anvende worker-pools, da det ofte er ineffektivt, så længe resten af serveren er designet rigtigt, f.eks. event-baseret. Hvis du er interesseret, kan jeg give nogle forslag til designmåder, men så må jeg vide lidt mere om systemet, f.eks. I/O; anvender du java.nio.*?
Ud fra den viste kode er der ikke meget at komme efter, det ser ud som det skal synes jeg...
grunden til workerthread er flere workers skal deles om arbejdet, de fleste opgaver er simple sql statements en worker fint kan klare alene, men engang imellem kommer der en tung en, og der kommer de flere workers ind, så de korte opgaver stadig udføres.
min klient laver et job, og kalder derefter getResult() getResult venter til isFinished er true, og sender så resultatet tilbage
Det der giver mest mening er at have en worker pr. tilgængelig database-forbindelse, og udover det kun have nok tråde til at servicere klienterne, altså læse fra netværksforbindelserne, udføre arbejde forbundet med modtaget data (lige pånær database-arbejde), og skrive data tilbage til klienterne. Men newer mind, det er ikke dit problem.
Din klient laver et job; har du en eller to tråde pr. klient? I stedet for at at kalde getResult() efter klienten har lavet et job (og lade tråden vente og spilde sin tid), vil det være bedre at have en callback-metode på Job, som kan workeren kan kalde, når database-kaldet er udført. På denne måde sparer du også ventemekanismen, der giver problemet.
public class WorkerPool { private Worker[] wrk; public WorkerPool(int n, Queue q) { wrk = new Worker[n]; for(int i = 0; i < wrk.length; i++) { wrk[i] = new Worker(q); wrk[i].start(); } } public void killAll() { for(int i = 0; i < wrk.length; i++) { wrk[i].interrupt(); } } }
package worker;
import java.io.*;
public class Test { private final static int N = 10000; public static void main(String[] args) throws Exception { String[] t = new String[N]; Queue q = new Queue(); WorkerPool pool = new WorkerPool(100, q); for(int i = 0; i < N; i++) { q.enqueue(new TestJob(i, t)); } while(!q.isDone()) { Thread.sleep(10); } pool.killAll(); PrintWriter pw = new PrintWriter(new FileOutputStream("C:\\t.lis")); for(int i = 0; i < t.length; i++) { pw.println(t[i]); } pw.close(); } }
Det er meget normalt at et objekt Job indeholder nogle info, sådan er det. Derimod er det meget mere værd, hvis man kan undgå at tråde venter på at nogle betingelser bliver opfyldt, men i stedet kan lave noget andet i mellemtiden. Husk at det klient-objekt Job-instancerne får med ikke er et objekt, men en reference til et objekt. Måske har du forøget en Job-instans' størrelse med 4-8 bytes, og det er virkelig ikke alverden.
Job repræsenterer jo en event i din server, som ændrer tilstand undervejs, hvilket betyder at nogle data må ændre værdier. Desuden er det pænt design, at Job indeholder alle de oplysninger der skal til for at jobbet kan fuldføres.
Og ja, det kan ofte være effektivt at mere end én forbindelse til samme database. Når du udfører et SQL-kald fra din Java-server til en database (f.eks. en query), hentes alle data i det returnerede ResultSet ikke med det samme, men løbende, efterhånden som ResultSet.next() kaldes. Det gør at flere forbindelser til samme database med fordel kan udnyttes. Husk at forbindelsen til databaser i Java er realiseret med en Socket, der somme tider vil være blokkeret i en eller anden I/O operation, imens har serveren mulighed for at kommunikere med databasen gennem andre forbindelser. Derved opnås bedre performance i forbindelse med database-kommunikationen.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.