# Zugriff auf ein Objekt mit mehreren Threads



## localhorst (19. Okt 2009)

Hallo,

habe mal wieder ein neues Problem.

Ich möchte mit einer grafischen Oberfläche Informationen eines Objekts darstellen.
Dieses Objekt braucht aber sehr viele Daten, die gleichzeitig mit mehreren Threads aus der Datenbank geholt werden müssen.

Das Zugreifen auf 1 Objekt mit mehreren Threads habe ich in einer Beispielapplikation (siehe unten) schon hinbekommen.. doch sobald die Datenbank ins Spiel kommt, geht es nicht.
es kommen sehr merkwürdige Sql Fehler wie z.B 

```
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
```
Der Sql Code ist aber ok.
hat jemand eine Idee warum es mit der Methode wie unten im Beispiel nicht funktioniert?
hat jemand eine andere Lösung um gleichzeitig Datenbankquerys durchzuführen?
Habe es auch schon mit Observerable und Observer versucht, doch da wird erst gar nicht auf das Notify reagiert.



```
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package threads;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    final Test test = new Test();

    public Main(){
        init();
    }

    private void init(){
      // Reihenfolge 4,3,2,1


      final Lock lock = new ReentrantLock();
      final Condition test2Set = lock.newCondition();
      final Condition test3Set = lock.newCondition();


        Runnable r1 = new Runnable() {

            public void run() {
                lock.lock();
                try{
                    test2Set.await();
                    test.setTest1();
                }
                catch(Exception e){
                    e.printStackTrace();
                }
                finally{
                    lock.unlock();
                }

            }
        };

        Runnable r2 = new Runnable() {

            public void run() {
                lock.lock();
                try{
                    test3Set.await();
                    test.setTest2();
                    test2Set.signal();
                }
                catch(Exception e){
                    e.printStackTrace();
                }
                finally{
                    lock.unlock();
                }

            }
        };

        Runnable r3 = new Runnable() {

            public void run() {
                lock.lock();
                try{
                    test.setTest4();
                    test.setTest3();
                    test3Set.signal();
                }
                catch(Exception e){
                    e.printStackTrace();
                }
                finally{
                    lock.unlock();
                }

            }
        };

        new Thread(r2).start();
        new Thread(r1).start();
        new Thread(r3).start();

    }



    public static void main(String[] args) {
        new Main();
        // TODO code application logic here

    }
    
    private class Test extends Object{
        private String test1;
        private String test2;
        private String test3;
        private String test4;
        
        public Test(){
            super();
        }
        
        void setTest1(){
            try {

                //Thread.sleep(42);
                this.test1 = "Test1";
                System.out.println("Thread : " + Thread.currentThread().getName() + " : " + test1);

            } catch (Exception ex) {
                ex.printStackTrace();
            }

        }

        void setTest2(){
            try {
                //Thread.sleep(2000);
                this.test2 = "Test2";
                System.out.println("Thread : " + Thread.currentThread().getName() + " : " + test2);
            } catch (Exception ex) {
                 ex.printStackTrace();
            }

        }

        void setTest3(){
            try {

                //Thread.sleep(1);
                this.test3 = "Test3";
                System.out.println("Thread : " + Thread.currentThread().getName() + " : " + test3);
                
            } catch (Exception ex) {
                 ex.printStackTrace();
            }

        }

        void setTest4(){
            try {

                //Thread.sleep(40);
                this.test4 = "Test4";
                System.out.println("Thread : " + Thread.currentThread().getName() + " : " + test4);

            } catch (Exception ex) {
                 ex.printStackTrace();
            }

        }


    }
}
```


----------



## Michael... (19. Okt 2009)

localhorst hat gesagt.:


> ```
> (SQLError.java:956)
> ```


Was steht den in der Zeile?


----------



## manuche (19. Okt 2009)

Michael... hat gesagt.:


> Was steht den in der Zeile?



das kommt ja nur aus dem SQL Package... Der komplette Stacktrace wäre interessant! Und vor allem wo in deinem Code oben was mit SQL vorkommt oder hab ich was überlesen?


----------



## localhorst (19. Okt 2009)

manuche hat gesagt.:


> das kommt ja nur aus dem SQL Package... Der komplette Stacktrace wäre interessant! Und vor allem wo in deinem Code oben was mit SQL vorkommt oder hab ich was überlesen?



Der Code oben ist generell nur ein Beispiel wie ich mit lock und notify, await die Threads steuere, und auf 1 object zugreife.
Stellt euch einfach vor, die Testmethoden sind Datenbankabfragen.

Ich kann leider kein anderes Beispiel posten, das wäre glaube ich viel zu unübersichtlich


----------



## manuche (19. Okt 2009)

Naja ne SQL-Exception kommt ja nicht von ungefähr... Wird schon seinen Grund haben warum die geschmissen wird! Poste mal am besten den ganzen Stacktrace der Exception!


----------



## localhorst (19. Okt 2009)

manuche hat gesagt.:


> Naja ne SQL-Exception kommt ja nicht von ungefähr... Wird schon seinen Grund haben warum die geschmissen wird! Poste mal am besten den ganzen Stacktrace der Exception!



at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
at com.mysql.jdbc.ResultSetImpl.checkRowPos(ResultSetImpl.java:815)
at com.mysql.jdbc.ResultSetImpl.getInt(ResultSetImpl.java:2593)
at com.mysql.jdbc.ResultSetImpl.getInt(ResultSetImpl.java:2734)
at mysamples.objectclasses.Boxen.setAllProben(Boxen.java:640)
at mysamples.programgui.BoxWindow$3.run(BoxWindow.java:192)
at java.lang.Thread.run(Thread.java:636)


hier, dazu muss ich sagen, dass die Exception nicht auftritt, wenn ich alle Abfragen nacheinander ohne Threads ausführe.


----------



## manuche (19. Okt 2009)

Ich könnte drauf wetten, dass es was mit dem abfeuern der Datenbankabfragen zu tun hat! Das ganze muss natürlich mindestens Threadsafe programmiert sein...
Am besten hast du natürlich eine zentrale Klasse die die Verbindung zur DB verwaltet und nach einander Statements abfeuert! Kommt jetzt halt drauf an wie du es umgesetze hast!


----------



## localhorst (19. Okt 2009)

manuche hat gesagt.:


> Ich könnte drauf wetten, dass es was mit dem abfeuern der Datenbankabfragen zu tun hat! Das ganze muss natürlich mindestens Threadsafe programmiert sein...
> Am besten hast du natürlich eine zentrale Klasse die die Verbindung zur DB verwaltet und nach einander Statements abfeuert! Kommt jetzt halt drauf an wie du es umgesetze hast!



Sowas vermute ich auch, wie könnte ich die Datenbank klasse Threadsafe umprogrammieren? habe sogut wie noch nie mit zusätzlichen Threads gearbeitet.


----------



## manuche (19. Okt 2009)

```
public class ModelConnection {
	private Connection con;
	
	public boolean createConnection(){
		try{
			Class.forName ("com.mysql.jdbc.Driver");
			String strCon = "jdbc:mysql://localhost:3306/blablubb";
			this.con = DriverManager.getConnection (strCon, "root", "");			
		}catch (ClassNotFoundException e){
			e.printStackTrace ();
			return false;
		}catch (CommunicationsException e) {
			e.printStackTrace();
			return false;
		}catch (SQLException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public boolean hasConnection(){
		if (this.con != null){
			try {
				if (!this.con.isClosed()){
					return true;
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return false;
	}
	
	public boolean closeConnection(){
		if (this.con != null){
			try {
				if (!this.con.isClosed()){
					this.con.close();
					return true;
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return false;
	}

	public synchronized ResultSet fetch (String query) throws SQLException {
		Statement stmt = this.con.createStatement();
		return stmt.executeQuery(query);
	}
}
```
ich würd es so oder so ähnlich probieren... Mit synchronized wird verhindert, dass meherere Threads gleichzeitig die Methode benutzen und das Abfeuern des Statements ist halt eine geschlossene Sache!


----------



## localhorst (19. Okt 2009)

manuche hat gesagt.:


> ich würd es so oder so ähnlich probieren... Mit synchronized wird verhindert, dass meherere Threads gleichzeitig die Methode benutzen und das Abfeuern des Statements ist halt eine geschlossene Sache!



Dankesehr, habe meine Datenbankklasse soweit umgebaut, leider kommt immernoch der gleiche Fehler, liegt es vielleicht doch an der Art, wie ich in den Runnables locke?


----------



## localhorst (20. Okt 2009)

Das Problem ist jetzt wie es scheint behoben, lag daran, dass ich 2 x await in einen Runnable hintereinander drin hatte und ich nicht wusste, dass es dann nicht mehr geht.
Warum es nicht geht, weiss ich jetzt immernoch nicht.

Naja und dann hatte ein noch einen ganz ärgerlichen Fehler, wusste nicht, dass man zuerst getResult.next() aufrufen muss, damit man überhaupt einen Datensatz bekommt, der Teil war in einer If Schleife for dem while(db.getResult().next()), wenn ich es ohne Threads ausgeführt habe, ist er nie rein gesprungen in die Schleife, da gewisse Daten schon vorhanden waren.
Trozdem war das mit der Synchronized  Methode in der Db Klasse hilfreich.

Danke für die Hilfe.


----------



## manuche (21. Okt 2009)

Die Datenbankklasse ist natürlich nur auf das nötigste reduziert und sehr sparsam!
Hat sich allerdings für mich in der Berufsschule bewährt... Copy-Paste und man hat das nötigste!


----------

