# Monitor Synchronisation eines Array



## Plastagen (8. Mai 2010)

Hey Leute,
ich habe folgendes Grundgerüst:


```
public class DruckdienstMonitor implements Druckdienst
{
	private final Drucker[] drucker;

	public DruckdienstMonitor(Drucker[] drucker) 
	{
		this.drucker = drucker;
	}

	public void drucke(String str) 
	{	
		
	}

}
```

Diese Klasse wqir mit 3 Druckern initialisiert. 
Dann laufen 5 Threads, die heweils 9 Dokumente "drucken" wollen.
Dabei darf ein Drucker ja nicht 2 Dokumente gleichzeitig drucken.

Meine Frage ist nun, wie kann ich Arrays so synchronisieren, dass immer nur ein Thread auf ein ArrayIndex zugreifen kann. Also zum Beispiel 
Thread 1 greift auf drucker[0] zu und Thread 2 auf drucker[1]

Mir ist klar, wie ich das gesamte Array synchronisieren kann aber dann kann immer nur 1 Thread auf das gesamte Array zugreifen, was ja nicht so gedacht ist.

Über Lösungsansätze wäre ich sehr dankbar, denn ich steh gerade total auf dem Schlacuh. =\

MfG Plastagen


----------



## Marco13 (8. Mai 2010)

Das geht so direkt nicht. Man kann auf ein einzelnes Objekt synchronisieren (also auch auf einen Array) aber eben nicht auf Arrayelemente. 

Du solltest dir vielleicht mal das java.util.concurrent Package ansehen, dort gibt es einige Hilfsklassen für sowas (BlockingQueue, im speziellen, da man das als einen Fall von "Producer-Consumer" ansehen könnte). Vermutlich wirst du eine Klasse brauchen, die sich um die Verteilung der Druckjobs an freie Drucker kümmert. Diese Klasse hätte also eine (Threadsichere) Methode 
void addSomethingToPrint(Something s)
die den Job an den ersten Freien Drucker weiterreicht, und falls kein Drucker frei ist, entweder wartet BIS einer frei ist, oder den Job in eine Queue legt, die von einem eigenen Thread abgearbeitet wird.


----------



## Plastagen (8. Mai 2010)

Erstmal Danke für die Antwort.
Anahnd dessen kam denn bei mir folgender Code zustande:


```
public class DruckdienstMonitor implements Druckdienst
{
	private final Drucker[] drucker;
	private DruckerVerteilung dv;

	public DruckdienstMonitor(Drucker[] drucker) 
	{
		this.drucker = drucker;
		this.dv = new DruckerVerteilung(drucker.length);
		
	}

	public void drucke(String str) 
	{
		int nr = dv.getDrucker();
		
		drucker[nr].drucke(str);
		dv.freeDrucker(nr);
	}
	
	private class DruckerVerteilung
	{		
		private int freiePlaetze;
		private boolean[] free;
		
		public DruckerVerteilung(int size)
		{
			this.freiePlaetze = size;
			this.free = new boolean[size];
			for(int i=0; i<size;i++)
			{
				this.free[i] = true;
			}
		}
		
		public synchronized int getDrucker()
		{
			int nr = 0;
			
			while(freiePlaetze == 0)
			{
				try 
				{
					wait();
				} catch (InterruptedException e) 
				{
					e.printStackTrace();
				}
			}
			freiePlaetze--;
			for(int i=0; i<free.length;i++)
			{
				if(free[i])
				{
					nr = i;
					free[i] = false;
					break;
				}
			}
			return nr;
		}
		
		public synchronized void freeDrucker(int nr)
		{
			free[nr] = true;
			freiePlaetze++;
			notify();
		}
	}
}
```

Also laut der Testklasse gibt es jetzt keien Überschneidungen mehr.
Ist nur die Frage, ob dies nach dem "Monitor"-Prinzip realisiert wird.

Meiner Meinung nach schon, da der Thread selbst ja nur sagt "Ich will drucken" und die Aufteilung findet dann in dieser annonymen Klasse "DruckerVerteilung" statt.

Wenn ich mich irre, korrigiert mich bitte.^^


----------



## Marco13 (8. Mai 2010)

Sieht beim schnellen Drüberschauen erstmal nicht "falsch" aus - müßte man nochmal im Detail prüfen, aber durch die beiden "synchronized"-Methoden kann da nicht mehr sooo viel falsch sein. Wenn du aber fragst, ob ... "dies nach dem "Monitor"-Prinzip realisiert wird", stellt sich erstmal die Frage, ob es dabei um ein praktisches Problem geht, oder ob das eine Hausaufgabe ist. Im letzteren Fall solltest du die genaue Aufgabenstellung posten. Im ersteren Fall _könnte_ man statt der "Druckverteilung" vielleicht besagte BlockingQueue verwenden, GANZ grob im Stil von

```
BlockingQueue<Drucker> drucker = ... // Am Anfang im Konstruktor mit allen Druckern füllen

public void drucke(String s)
{
    Drucker d = druckerQueue.take(); // Blockiert falls keiner mehr frei
    d.drucke(s);
    druckerQueue.put(d);
}
```
Das könnte kompakter und einfacher sein, weil die Druckverteilung im Moment eigentlich nur "von Hand" eine ähnliche(!) Funktionalität erfüllt, wie eine BlockingQueue


----------



## Plastagen (8. Mai 2010)

Ich habe es schon mti Absicht in den "Hausaufgaben"-Teil des Forums gepostet.^^
Die Aufgabe dazu lautet:



> Ein Druckdienst soll eingehende Druckaufträge auf eine feste Anzahl von Druckern verteilen. Dabei
> muss der Druckdienst dafür Sorge tragen, dass jeder Drucker stets nur maximal einen Auftrag
> zur Zeit verarbeitet. Der Druckdienst kann von mehreren Prozessen bzw. Threads gleichzeitig
> aufgerufen werden, wobei der Aufruf solange blockiert, bis das Dokument gedruckt wurde.
> ...



Spricht wir haben schon den größten Teil vorgegeben und sollen nur das Interface "Druckdienst" für die 3 Synchronisationsprinzipien "Test and Set Lock", "Semaphore" und "Monitore" implementieren.

Und da es sich bei dem Modul um "Grundlagen der Systemsoftware" handelt, glaube ich eher nicht, dass wir das mit einer BlockingQueue unbedingt realisieren sollen.
In der Vorlesung hatte er das auch mit dem Beispiel "Producer-Customer" vorgestellt.


----------



## Plastagen (8. Mai 2010)

Also vielen Dank für deine Hilfe, Marco13.
Ich sehe die Aufgabe jetzt als gelöst an und der Thread kann geschlossen werden.

MfG Plastagen


----------



## Marco13 (8. Mai 2010)

Plastagen hat gesagt.:


> Ich habe es schon mti Absicht in den "Hausaufgaben"-Teil des Forums gepostet.^^


Hatte ich übersehen ... passiert mir irgendwie öfter...


----------



## Plastagen (9. Mai 2010)

Ach kein Problem. Kann jedem mal passieren.


----------

