[Java] en Threads

Pagina: 1
Acties:

  • Darkvater
  • Registratie: Januari 2001
  • Laatst online: 26-08-2024

Darkvater

oh really?

Topicstarter
Ik ben al de hele dag bezig met iets in Java proberen te implementeren, maar het wil we maar niet lukken. Ik probeer het volgende te doen: in main een nieuwe database object aanmaken en daar een thread aanmaken die de database connectie probeert te openen. Dan de main thread 10 seconden laten slapen. Als in de tussentijd StartDB_Thread geen notify() heeft gedaan dan zeg ik dat er een timeout is gebeurd en de database niet bereikbaar is. Het probleem is dat die notify() mijn slapende main niet wakker maakt. Ik doe vast iets fout... maar wat?

Helaas moet ik het zo doen omdat DriverManager.setLoginTimeout() niet is geimplementeerd voor HSQLDB en ik anders gewoon 3-4 minuten moet wachten op de connectie als er iets niet klopt. Ook weet ik dat T.stop() niks zal doen omdat de thread is geblokkeerd in een I/O operatie, maar het is alleen een beetje geklungel daar.

In C zou ik het zo doen met gewoon een Event en WaitForSingleObject(), maar kennelijk werkt dat hier anders :(.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class Database implements Runnable {
  Connection conn;
  Statement st;

  public void run() {StartDB_Thread();}

  public synchronized void StartDB_Thread() {
    try {
    Class.forName("org.hsqldb.jdbcDriver");
    System.out.println("Opening database connection...");
    this.conn = DriverManager.getConnection(conn_string, "sa","");
    System.out.println("Database connection opened");
    this.st = this.conn.createStatement();
    } catch (Exception e) {
      System.out.println("Exception occured (run)");
      e.printStackTrace();
    } finally {
      System.out.println("Waking up waiting thread...");
      notify();
    }
  }

  public synchronized void Database1() throws Exception {
    Thread T = new Thread(new Database());
    T.start();
    System.out.println("Database thread started");
    try {
      System.out.println("Database waiting [S]");
      wait(10000);
      System.out.println("Database waiting [E]");
      T.stop();
    } catch (Exception e) {
      System.out.println("Timeout exception occured...");
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    Database db = null;

    try {
      db = new Database();
      db.Database1();
    } catch (Exception ex) {
      ex.printStackTrace();
      return;
    }
  }


Windows Vista? *NEVER* Het waarom - Opera forever!!!
I've seen chickens that were more menacing. Chickens in a coma. On ice. In my fridge


  • DaRKie
  • Registratie: December 2001
  • Laatst online: 12-02 09:57
Verander dit:
Java:
1
Thread T = new Thread(new Database());


naar:
Java:
1
Thread T = new Thread(this));


probleem is dat je synched methods een andere mutex locken:
als je de wait() aanroept, is de lock op het eerste object van Database
maar je thread geef je een nieuw object mee van Database, de notify die dan gebeurt is die voor het 2de object en zodoende blijft het eerste object wachten.

  • Darkvater
  • Registratie: Januari 2001
  • Laatst online: 26-08-2024

Darkvater

oh really?

Topicstarter
DaRKie schreef op woensdag 20 september 2006 @ 15:45:
Verander dit:
Java:
1
Thread T = new Thread(new Database());


naar:
Java:
1
Thread T = new Thread(this));


probleem is dat je synched methods een andere mutex locken:
als je de wait() aanroept, is de lock op het eerste object van Database
maar je thread geef je een nieuw object mee van Database, de notify die dan gebeurt is die voor het 2de object en zodoende blijft het eerste object wachten.
Ah dank je wel, dat werkt als de Database connectie goed gaat. Alleen twee vragen: ik dacht dat wait() een InterruptedException gooide als het een modify kreeg voor de timeout afliep. Ook lijkt het met 'Thread(this)' de timeout van wait niks uit te maken, het blijft maar wachten... volgens mij is mijn hele concept fout voor het oplossen van het probleem. Bleh.

Ik krijg namelijk de volgende output bij een successvolle connectie:
code:
1
2
3
4
5
6
Database thread started
Database waiting [S]
Opening database connection...
Database connection opened
Waking up waiting thread...
Database waiting [E]

Als er een InterruptedException was dan zou "Database waiting[E]" niet geprint mogen worden.

Bij een foute connectie:
code:
1
2
3
Database thread started
Database waiting [S]
Opening database connection...

En dat duurt ongeveer 3-4 minuten.

[ Voor 20% gewijzigd door Darkvater op 20-09-2006 19:32 ]


Windows Vista? *NEVER* Het waarom - Opera forever!!!
I've seen chickens that were more menacing. Chickens in a coma. On ice. In my fridge


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

Alarmnummer

-= Tja =-

Ik heb inhoudelijk niet naar de code gekeken want ik kreeg al enorme hoofdpijn van het ontwerp. Probeer de threading niet in je classes te laten doorlekken als dat kan. In jouw geval zou ik dus die Database geen runnable interface laten implementeren, maar hem vragen om een 'connectie' runnable eventueel. Of een methode 'connect' die jij dan extern op een thread laat lopen (mij favoriet).

Op die manier blijft je ontwerp een stuk schoner.

[edit]
en die main ook niet bij je classes inproppen. Die hoort daar niet, maak dus ff een aparte Main class aan.

[ Voor 12% gewijzigd door Alarmnummer op 20-09-2006 20:35 ]


  • Darkvater
  • Registratie: Januari 2001
  • Laatst online: 26-08-2024

Darkvater

oh really?

Topicstarter
Alarmnummer schreef op woensdag 20 september 2006 @ 20:33:
Ik heb inhoudelijk niet naar de code gekeken want ik kreeg al enorme hoofdpijn van het ontwerp. Probeer de threading niet in je classes te laten doorlekken als dat kan. In jouw geval zou ik dus die Database geen runnable interface laten implementeren, maar hem vragen om een 'connectie' runnable eventueel. Of een methode 'connect' die jij dan extern op een thread laat lopen (mij favoriet).

Op die manier blijft je ontwerp een stuk schoner.

[edit]
en die main ook niet bij je classes inproppen. Die hoort daar niet, maak dus ff een aparte Main class aan.
Ik moest de connectie testen, had dus geen tijd om mooie classes en what not te maken. Maar zal dat helpen of verdoe ik gewoon een heleboel tijd aan OOP etc. en blijf ik met hetzelfde probleem zitten?


Windows Vista? *NEVER* Het waarom - Opera forever!!!
I've seen chickens that were more menacing. Chickens in a coma. On ice. In my fridge


  • DaRKie
  • Registratie: December 2001
  • Laatst online: 12-02 09:57
Zoals alarmnummer zegt is jou code niet het voorbeeld van hoe het moet, maar ik begrijp dat dit meer een testcase is dus daarom dat ik ff verder help:

als je de API van Object() bekeken had, dan zou je zien dat wait() de InterruptedException gooit als hij interrupted is, dit gebeurt dmv interrupt(). Notify zal de wait() laten verder gaan en dus geen exceptie throwen. Interupt zal dus de hele wait block stoppen waarbij notify het zal laten verdergaan.

Wat dit betekend met je huidige uitkomst:
- wait() laat de lock op de mutex los
- bijgevolg kan de thread starten omdat die nu wel de lock krijgt op de mutex (mutex is in beide gevallen het Database object)
- je database connectie lijkt mij niet te werken en blijft proberen te connecten

Nu, jij wilt dat de wait dan na 10 seconden stopt met wachten, dit is niet mogelijk:
als wait() wilt verdergaan moet het eerst terug de lock op de mutex krijgen MAAR deze is nog steeds in bezit van de thread die probeert te connecteren, conclusie: deathlock :)

Oplossing:
- verwijder de synchronized keyword van de startdb_thread methode
- laat die methode pas de lock op de mutex vragen als hij wil gaan notifyen:
Java:
1
2
3
synchronized (this) {
    notify();
}


Moest deze class een essentieel onderdeel gaan vormen van je applicatie:
- bekijk eens degelijk hoe Threads werken want zelfs met mijn aanpassing zal het nog niet werken zoals jij wilt ( er gaat immers nooit een exception gegooid worden, enkel wait zal verder gaan dus je ziet geen verschil of de connectie nu werkt of niet). En het is niet omdat iets werkt, dat je threadsafe bezig bent.
- maak een degelijk model
- en please, hou je aan de coding guidelines, de namen van je methods en vars zijn not done
Pagina: 1