Monitor Synchronisation eines Array

Plastagen

Mitglied
Hey Leute,
ich habe folgendes Grundgerüst:

Java:
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

Top Contributor
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

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

Java:
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

Top Contributor
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
Code:
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

Mitglied
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.
Ein solcher Druckdienst soll in Java implementiert werden.
Dazu finden Sie auf der Website ein Paket mit einigen Hilfklassen, die für die Implementierung verwendet werden sollen

c) Monitor (15 Punkte)
Da der Umgang mit Semaphoren genaue Aufmerksamkeit erfordert, besitzen moderne Programmiersprachen
das sprachliche Konstrukt Monitor. Auch Java verfügt über entsprechende
Konstrukte und Methoden. Verwenden Sie diese um den Druckdienst zu implementieren
(DruckdienstMonitor). Verwenden Sie dabei keine anderen Konstrukte zur Synchronisation,
wie beispielsweise TSL, Semaphore oder Mutex. Das Verwenden von aktivem Warten
ist nicht erlaubt.

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

Mitglied
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
 

Oben