Semaphoren?

MaxReeb

Grünschnabel
Hi,

zum Besseren Verständnis des Semaphoren Prinzips habe ich ein kleines Producer, Consumer Beispiel geschrieben. Habe als ersten Ansatz die Beispielklasse Pool für mein Beispiel verwendet. Allerdings funktioniert es nicht richtig.

Eigentlich sollten beide Akteure abwechslend agieren. Wenn der Puffer leer ist, sollte der Consumer warten, wenn der Puffer voll ist der Producer. Die Synchronisation soll durch Verwendung von java.util.concurrent.Semaphore erreicht werden. Wie aber anhand der Ausgabe zu erkennen ist, arbeitet irgendwann nur noch der Producer nicht jedoch der Consumer.

LG Max

http://java.sun.com/javase/6/docs/api/java/util/concurrent/Semaphore.html


//Pool.java
Java:
import java.util.concurrent.Semaphore;

public class Pool {
	private static final int MAX_AVAILABLE = 10;

	private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);

	protected Object[] items = new Object[MAX_AVAILABLE];

	protected boolean[] used = new boolean[MAX_AVAILABLE];
	
	public Pool() {
		for (int i = 0; i < MAX_AVAILABLE; i++) {
			items[i]= "Apfel"; 
		}
	}
	
	public Object getItem() throws InterruptedException {
		System.out.println("available.aquire() start");
		available.acquire();
		System.out.println("available.aquire() end");
		return getNextAvailableItem();
	}

	public void putItem(Object x) {
		if (markAsUnused(x)) {
			System.out.println("available.release() start");
			available.release();
			System.out.println("available.release() end");
		}
	}

	protected synchronized Object getNextAvailableItem() {
		for (int i = 0; i < MAX_AVAILABLE; ++i) {
			if (!used[i]) {
				used[i] = true;
				return items[i];
			}
		}
		return null;
	}

	protected synchronized boolean markAsUnused(Object item) {
		for (int i = 0; i < MAX_AVAILABLE; ++i) {
			if (item == items[i]) {
				if (used[i]) {
					used[i] = false;
					return true;
				} else
					return false;
			}
		}
		return false;
	}
}

// Producer.java
Java:
import java.util.Random;

public class Producer extends Thread{
	
	private Pool pool;
	
	private String[] fruit = {"apple", "pear", "strawberry"};
	
	public Producer(Pool pool) {
		this.pool = pool;
	}
	
	public void run(){
		Random r = new Random();
		
		while(true){
			String s = fruit[r.nextInt(fruit.length)];
			System.out.println("Producer put: " + s);
			pool.putItem(s);
			
			try {
				Thread.sleep((long)r.nextInt(1000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

// Consumer.java
Java:
import java.util.Random;

public class Consumer extends Thread{
	
	private Pool pool;
	
	private String[] fruit = {"apple", "pear", "strawberry"};
	
	public Consumer(Pool pool) {
		this.pool = pool;
	}
	
	public void run(){
		Random r = new Random();
		
		while(true){
			try {
				System.out.println("Consumer get and eat: " + pool.getItem().toString());
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			
			try {
				Thread.sleep((long)r.nextInt(1000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

// Lunch.java
Java:
public class Lunch {

	public static void main(String[] args) {
		Pool pool = new Pool();
		Producer p = new Producer(pool);
		Consumer c = new Consumer(pool);
		
		c.start();
		p.start();
	}
}

Ausgabe:
Code:
available.aquire() start
available.aquire() end
Consumer get and eat: Apfel
Producer put: apple
available.aquire() start
available.aquire() end
Consumer get and eat: Apfel
available.aquire() start
available.aquire() end
Consumer get and eat: Apfel
available.aquire() start
available.aquire() end
Consumer get and eat: Apfel
Producer put: strawberry
available.aquire() start
available.aquire() end
Consumer get and eat: Apfel
available.aquire() start
available.aquire() end
Consumer get and eat: Apfel
Producer put: apple
available.aquire() start
available.aquire() end
Consumer get and eat: Apfel
available.aquire() start
available.aquire() end
Consumer get and eat: Apfel
Producer put: strawberry
available.aquire() start
available.aquire() end
Consumer get and eat: Apfel
Producer put: strawberry
available.aquire() start
available.aquire() end
Consumer get and eat: Apfel
Producer put: apple
available.aquire() start
Producer put: strawberry
Producer put: strawberry
Producer put: strawberry
Producer put: apple
Producer put: strawberry
Producer put: strawberry
Producer put: apple
Producer put: strawberry
Producer put: strawberry
Producer put: apple
Producer put: pear
Producer put: strawberry
 
Hi,
ich versuch das Producer Consumer Problem anhand von
einem Beispiel mal zu erklären:

Was haben wir:
Braumeister -> Producer
Student -> Consumer
Raum -> Zwischenpuffer der Synchronisiert werden soll.

Der Raum hat eine Tür und es Gibt einen Schlüssel zu
dem Raum. In dem Raum wird das Bier gelagert. ^^

Es darf maximal 1 Person gleichzeitig im Raum sein.
Entweder :
der Braumeister um Bier rein zu stellen.
oder der Student um sich welches zu holen.

Wenn jetzt also jemand auf den Raum ( das wäre in deinem Beispiel
der Pool ) zugreifen will, dann muss er zu Beginn den Schlüssel
holen. Nur wenn er den hat kann er den Raum betreten.
Wenn er den Raum verläst gibt er den Schlüssel wieder zurück
und jemand anderst kann ihn sich nehmen.
( aber auch die selbe Person nochmals.. )

Jetzt schaut der Consumer solange er drann ist allerdings die
Ganze Zeit in den Ruam anstatt sich schlafen zu legen. Auch
wenn dieser leer ist. ( genau so beim Producer ).

Überleg einfach mal wie du es das am geschicktesten
lösen würdest.

Gruß Benny
 
Hi Benny,

das Producer, Consumer Szenario ist mir schon klar. Das selber programmieren müsste auch das kleinste Problem sein. Entweder mit Busy Waiting oder abfragen der Puffergröße ob im Puffer etwas drin ist oder nicht.

Mir geht es hier um Semaphoren!
http://de.wikipedia.org/wiki/Semaphor_(Informatik)

Hierzu bietet das JDK seit Version 5.0 die Klasse:
http://java.sun.com/javase/6/docs/api/java/util/concurrent/Semaphore.html

Wie wende ich diese Klasse richtig an, um bspw. ein Producer/Consumer Synchronisationsproblem zu lösen? Da liegt mein Problem!

[EDIT]

Habe hier noch ein Beispiel zu der Klasse gefunden:
http://www.galileocomputing.de/open...09_006.htm#mj401fd3443bf352cb8857c8425b0f1a79

Werde mal versuchen anhand diesem das Producer/Consumer Beispiel neu zu schreiben.


LG Max
 
Zuletzt bearbeitet:
WEnn du Das Consumer Producer Problem versstanden hast
dann schau dir doch nochmal deinen Pool an und dann meine
Erklärung. Das ist nicht das gleiche.

Before obtaining an item each thread must acquire a permit from the semaphore, guaranteeing that an item is available for use. When the thread has finished with the item it is returned back to the pool and a permit is returned to the semaphore, allowing another thread to acquire that item.

Das hier steht bei der Beschreibung des Pools den du genommen hast.
In diesem Beispiel gibt es keinen Producer und keinen Consumer sondern
nur Threads die einen Zugriff auf die Ressource haben wollen.
Und wenn sie fertig sind dann legen Sie die Ressource wieder in den Pool.

Dein Consumer würde also einen Apfelbutzen zurücklegen ^^

Die Ressource die du mit einer Semaphore schützen musst sind nicht
die einzelnen Elemente im Pool sondern den Pool ansich. Und diesen Pool gibt es genau 1 mal.
 
Zurück