# Threads am Beispiel Parkhaus



## Montra (22. Jan 2012)

Hallo,

ich versuche mich derzeit an Threads und habe ein paar Schwirigkeiten auf die richtige Idee zu kommen.
Ich wollte zum üben ein Parkhaus simulieren. Hierzu habe ich erstmal eine Klasse Car erstellt. Diese Klasse Car stellt ein Auto dar, es soll zunächst eine zufällige Zeit lang herumfahren und anschließend versuchen mit der Methode enter () ins Parkhaus einzufahren.

Das Parkhaus hat ein Boolean Array mit 10 Slots. Darin wird gespeichert welcher Platz belegt ist und welcher frei ist. Zunächst initialisiere ich dort dieses Array und außerdem ein Array aus 20 Cars.

Die Autos sollen wie schon erwähnt nach einer zufälligen Wartezeit ("rumfahren") versuchen ins Parkhaus zu gelangen, wenn ein Platz frei ist, sollen sie für eine zufällige Zeit dort parken (solange ist dieser Platz natürlich besetzt) und dann wieder aus dem Parkhaus hinaus fahren, wodurch wieder ein Platz frei wird.
Wenn allerdings kein Platz frei ist, soll das Auto für eine zufällige Zeit lang warten und dann erneut versuchen ins Parkhaus zu gelangen.

Ich komme nicht darauf wie ich das genau realisieren kann.

Bisher habe ich das hier:

Car:

```
public class Car extends Thread
{
	public int mId;
	
	public Car (int aId)
	{
		mId = aId;
	}
	
	public void run ()
	{
		System.out.println("Auto " + mId + " fährt rum!");
		try
		{
			sleep ((long)Math.random() * 10000);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		System.out.println("Auto " + mId + " will ins Parkhaus!");
	}
	
	public void enter ()
	{
		System.out.println("Auto " + mId + " fährt ins Parkhaus!");
	}
	
	public void carWait ()
	{
		System.out.println("Auto " + mId + " wartet!");
		try
		{
			sleep ((long)Math.random() * 10000);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		System.out.println("Auto " + mId + " versucht es nochmal!");
	}
	
	public void leave ()
	{
		System.out.println("Auto " + mId + " verlässt Parkhaus!");
	}
}
```

ParkHouse:

```
public class ParkHouse 
{
	private boolean[] isFree = new boolean[10];
	Car cars[] = new Car[20];
	
	public void init ()
	{
		for (int i = 0; i < isFree.length; i++)
		{
			isFree[i] = true;
		}
		for (int i = 0; i < cars.length; i++)
		{
			cars[i] = new Car (i+1);
		}
	}
	
	public void open ()
	{
		System.out.println("Das Parkhaus öffnet!");

		
		System.out.println("Das Parkhaus schließt!");
	}
	
	public boolean checkIsFree () 
	{
		for (int i = 0; i < isFree.length; i++)
		{
			if (isFree[i] == true)
			{
				return true;
			}
		}
		return false;
	}
}
```


----------



## njans (22. Jan 2012)

Nun du musst generell erstmal den Zugriff auf das ParkHouse Objekt erlauben, damit dort überhaupt Methoden von aufgerufen werden können.
Danach sollten so einige Methoden Synchronisiert werden und du wirst wohl auch synchronized Blöcke brauchen. Ebenfalls fehlen da noch so einige while schleifen (sonst wartet ein Auto ja immer nur ein mal!).

Hilft das schon weiter?


----------



## Montra (22. Jan 2012)

Das ganze soll erstmal ohne Schnickschnack wie synchronized laufen 

Mein Problem ist, wie ich alle Autos gleichzeit starten kann und sie quasi (mit Berücksichtigung der Wartezeit) alle gleichzeitig aufs Parkhaus zugreifen wollen. Eine bestimmte Reihenfolge ist völlig egal, Hauptsache jedes Auto schafft es ersmtal einmal zu parken.


----------



## Tobias (22. Jan 2012)

Anbei die Musterlösung zu einer Aufgabe aus der Nachklausur "Betriebssysteme für Medieninformatiker", die sich mit einem ganz ähnlichen Problem beschäftigt.

Musterlösung


----------



## Montra (22. Jan 2012)

Jedes Auto hat eine eigene Werkstatt?^^


----------



## Tobias (22. Jan 2012)

Nein, aber jedes Auto muss die eine existente Werkstatt kennen.


----------



## JavaProfi (22. Jan 2012)

Hi montra,
hier mal eine mögliche rapid code variante.
Vielleicht hilft dir das weiter.

[Java]
public class CarWorld {

	static private ParkHouse parkhaus;

	public static void main(String[] args) {
			parkhaus = new ParkHouse();
			for (int id = 1; id <= 20; id++){
				new Car(id, parkhaus).start();
			}
	}

}
[/Java]

[Java]
public class Car extends Thread
{
    private int id;
    private ParkHouse parkhaus;
    private boolean keepAlive = true;

    public Car (int id, ParkHouse parkhaus){
        this.id = id;
        this.parkhaus = parkhaus;
    }

    public void run ()
    {
    	fahren();
    	while(keepAlive){
   			if(einparken() == true){
   				System.out.println("Auto " + id + " will ins Parkhaus!");
   				parken();
   				ausparken();
   				fahren();
   			}
   			else
   				System.out.println("Auto " + id + ": Parkhaus voll!");
   				fahren();

   			if (this.isInterrupted()){
            	parkhaus.ausparken(this);
            	keepAlive = false;
            }

    	}
    }

    private void fahren (){
    	System.out.println("Auto " + id + " fährt rum!");
		warten();

    }
    private boolean einparken(){
    	boolean parkTicket = parkhaus.einparken(this);
    	System.out.println("Auto " + id + " parkt ein!");
    	return parkTicket;
    }

    private void parken(){
    	System.out.println("Auto " + id + " parkt!");
    	warten();
    }

    private void ausparken()  {
    	parkhaus.ausparken(this);
    	System.out.println("Auto " + id + " parkt aus!");
    }

    private void warten(){
    	try {
         	Thread.sleep ((long)Math.random() * 20000);
 		} catch (InterruptedException e) {
 			keepAlive = false;
 		}
    }
}
[/Java]

[Java]
public class ParkHouse 
{
    private Car[] parkboxes;

    public ParkHouse (){
    	parkboxes = new Car[10];
       }


    public synchronized boolean  einparken(Car activeCar) 
    {
    	boolean result = false;

        for (int i = 0; i < parkboxes.length; i++){
        	if (parkboxes_ == null){
            	parkboxes = activeCar;
            	result = true;
            	break;
            }
        }
        return result;
    }

    public void ausparken(Car activeCar){
    	 for (int i = 0; i < parkboxes.length; i++){
    		 if (parkboxes != null) {
    			 if (parkboxes.equals(activeCar)){
    				 // Parkplatz freigeben
    				 parkboxes = null;
    				 break;
    			 }
             }
         }
    }
}
[/Java]

Gruss
JP_


----------



## Montra (22. Jan 2012)

@Tobias

Danke für das Beispiel, allerdings arbeitet es mit synchronized, was ich noch nicht einsetzen wollte.
Außerdem macht das Programm keine korrekten Ausgaben, was die Anzahl der Autos in der Werkstatt betifft. Bsp-Ausgabe:

KB-X 123 angenommen!
0
HH-H 666 angenommen!
1
KB-X 123 abgegeben!
2

Nach dem das Auto abgegeben wurde, wurde hier der Count um 1 erhöht. Also scheint dort irgendwas mit der zeitlichen Abstimmung nicht zu klappen.

@Javaprofi

Danke ebenfalls für die Hilfe, jedoch wie bei Tobias mit synchronized


----------



## JavaProfi (22. Jan 2012)

Montra hat gesagt.:


> @Tobias
> 
> Danke für das Beispiel, allerdings arbeitet es mit synchronized, was ich noch nicht einsetzen wollte.
> Außerdem macht das Programm keine korrekten Ausgaben, was die Anzahl der Autos in der Werkstatt betifft. Bsp-Ausgabe:
> ...



Du kommst um synchronized nicht herum wenn du mit Threads auf einer gemeinsamen Datenstruktur arbeitest!!!

Synchronized ist kein Schnickschnack sondern notwendig!
Gruß
JP


----------



## Tobias (25. Jan 2012)

Ohne synchronized wird es nicht gehen, außer du baust dir irgendwas mit Hilfe des Concurrent-Packages zusammen (was aber auch nur synchronized in besser versteckt ist).

Die "falschen" Ausgaben entstehen durch die Verwendung des Postfix-Operators "++" bzw "--" und haben nichts mit der zeitlichen Abfolge zutun.


----------



## Lumaraf (25. Jan 2012)

JavaProfi hat gesagt.:


> [Java]
> public class ParkHouse
> {
> /* ... */
> ...


_

Die Methode ParkHouse#ausparken kann btw eine NullPointerException liefern wenn zwischen beiden if Abfragen von einem anderen Thread der entsprechende Index auf null gesetzt wird. Man muß an allen Stellen an denen mehrere Threads veränderbare Daten zugreifen können in irgendeiner Weise die Zugriffe untereinander koordinieren. (mittels synchronized oder einer passenden Klasse aus java.util.concurrent)_


----------

