Parallele Konzepte in Java

MatheStein

Aktives Mitglied
Hey Leute,

ich habe eine Frage zu den Parallelitätskonzepten in JAVA und zwar bietet Java einem Funktionen wie wait/notify für die Threadübergreifende Signalisierung und Verständigung.
Ich verstehe voll und ganz den Sinn bzw. die zugrundeliegende Intuition hinter wait/notify, wundere mich aber etwas, dass es keine Möglichkeit gibt so etwas wie wait/notify ohne lock zu nutzen, d.h. Signalisierungen aus Blöcken heraus in denen nicht synchronisiert wird, in JAVA zu nutzen.
So wie ich das verstanden habe sind wait/notify stets ein einen lock gebunden, da wait meist eine zu überprüfende Bedingung (meist eine while-Schleife) vorausgeht und es evtl. ungünstig wäre, wenn ein fremder Thread sich zwischen der Bedingungsüberprüfung und dem wait schaltet.
Was ist aber, wenn ich keine Bedingung vorher in diesem Sinne überprüfen muss?
Einfachstes Beispiel wäre hier evtl der Versuch eine simple Barriere mittels wait/notify nachzuprogrammieren.
Stellen wir uns dafür zwei Threads T_1 und T_2 vor, welche wir an einem bestimmten Punkt synchronisieren möchten, von der wir aus irgendeinem Grund wissen, dass T_1 diesen Punkt als erstes erreich wird. Man könnte an dieser Stelle dann einfach wait in T_1 aufrufen und an der korrespondieren Stelle in T_2 einfach ein notify.
Die Bedingung wäre dann, dass T_1 entsprechende Stelle erreicht und es wäre kein while und somit auch kein lock nötig beim Aufruf von wait.

Zusammenfassend:
Aus welchem Grund werden einem im Java keine primtiven Singnalisierungs-Konzepte zur Verfügung gestellt, welche sich entsprechend zu wait/notify verhalten und unabhängig von einem lock sind?
Auch in der Literatur zur parallelen Programmierung werden in der Regel zunächst simple Singnalisierungs-Konzepte vorgestellt (welche unabhängig von einem lock sind) und anschließend aufbauend Singnalisierungs-Konzepte welche implizit mit Locks umgehen können, d.h. diese implizit freigeben und wieder anfordern (wie in JAVA wait/notify)


Vielen Dank für eure Mühe im Voraus.


Beste Grüße
 
Es hält dich niemand auf ein wait(), notify() ohne irgendeine Bedingung abzusetzen. Das Lock auf
das Monitorobjekt benötigst du deshalb, weil du dich mit wait() in die "Warteschlange" des
Monitorobjekts einordnest.
Das man öfter eine Bedingung in einer while-Schleife sieht bei der man glaubt das mache keinen
Sinn hat etwas mit sog. spurious wakeups und missed signals zu tun.

Und was sind für dich primitive Signalisierungskonzepte? Da du schon von Literatur sprichst, die
primitive Signalisierungskonzepte ohne Synchronisation zwischen parallelen Aktivitäten
beschreiben, wären Quellen und Definitionen angebracht um eine einheitliche Vorstellung zu
entwickeln.
 
Danke für deine Antwort 🙂

wait und notify können nie aus einem nicht synchronisierten Bereich aufgerufen (es wird eine Exception geworfen). Das "Problem" ist, dass sofern der lock nicht nötig sein sollte und man diesen künstlich anfordert damit man wait/notify nutzen kann, es zu Performance-Verlusten kommt (sowie einem unschönen Design), da man unnötig sequentialisieren würde.

Literatur findet man z.B. hier:
http://pvs.uni-muenster.de/pvsarchive/lehre/WS09/bs/folien/bs4.pdf

Hier findet man einmal eine "primtive" von einem lock unabhängige Signalisierung auf Seite 6 und folgende.
Auf Seite 41 findet man dann bedingte Synchronisation, welche den Signalisierungen auf Seite 6 entsprechen mit dem Unterschied, dass diese implizit mit locks umgehen können, d.h. zu entsprechender Zeit ein lock passend anfordern und auch wieder freigeben (und entsprechen somit i.W. wait/notify aus JAVA)


Viele Grüße
 
Danke für deine Antwort 🙂

wait und notify können nie aus einem nicht synchronisierten Bereich aufgerufen (es wird eine Exception geworfen). Das "Problem" ist, dass sofern der lock nicht nötig sein sollte und man diesen künstlich anfordert damit man wait/notify nutzen kann, es zu Performance-Verlusten kommt (sowie einem unschönen Design), da man unnötig sequentialisieren würde.

Literatur findet man z.B. hier:
http://pvs.uni-muenster.de/pvsarchive/lehre/WS09/bs/folien/bs4.pdf

Hier findet man einmal eine "primtive" von einem lock unabhängige Signalisierung auf Seite 6 und folgende.
Auf Seite 41 findet man dann bedingte Synchronisation, welche den Signalisierungen auf Seite 6 entsprechen mit dem Unterschied, dass diese implizit mit locks umgehen können, d.h. zu entsprechender Zeit ein lock passend anfordern und auch wieder freigeben (und entsprechen somit i.W. wait/notify aus JAVA)


Viele Grüße

Der verlinkte Text ist relativ low-level auf Betriebssystemebene ausgelegt. Die JVM ist alles andere als
ein OS. Da muss man differenzieren, da alles viel abstrakter gehalten wird. Ich bin auch nicht ganz
mit dem Vokabular einverstanden. Z.B. das Verständnis Prozess vs. Thread, im Java-Umfeld wird das
wie folgt verstanden: Processes and Threads (The Java™ Tutorials > Essential Classes > Concurrency).

Zurück zu deiner Darstellung. Bei der wait()/notify()-Geschichte geht es um einen sog. "condition
queue" der einer Menge von Threads erlaubt auf eine spezielle Bedindung zu warten. Eine
"Monitorvariable" (auf die synchronisiert wird) ist gleichzeitig ein "condition queue" das bedeutet um
eine Methode (wait/notify) auf dem queue aufrufen zu können benötigst du das Lock auf ebendiesen
und somit implizit auf die "Monitorvariable" selbst. Um die Geschwindigkeit würde ich mir da jetzt nicht
wirklich Gedanken machen, da du für weitere Aktionen sowieso das Lock benötigst.

Zu den Folien. Die in den Folien beschriebene Signalisierung ist nichts weiter als ein Mutex, d.h. es
gibt doch einen Synchronisationspunkt. Und eine adäquatere Lösung für das P1/P2 Beispiel in Java
wäre wohl eine einfache Semaphore, wie im unteren Beispiel.

Des Weiteren betrachte ich die "nachgebauten" Parallelitätssteuerungsinstrumente als kritisch. Du
kannst ja selbst nachsehen wie z.B. ein Lock (ReadLock z.B.) in Java realisiert ist. Das sieht ein
wenig anders aus.

Java:
import java.util.concurrent.Semaphore;

public class SemaphoreBeispiel {
    private final static Semaphore sem = new Semaphore(0);

    public static void main(String args[]){
        Thread p1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Ich muss vor der Ausgabe in p2 laufen!");
                sem.release();
            }
        });

        Thread p2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    sem.acquire();
                    System.out.println("Ich bin die Ausgabe in p2!");
                } catch (InterruptedException e) {
                    //für Bsp. nichts tun
                }
            }
        });


        p2.start();
        p1.start();
//      p1.start();
//      p2.start();
    }
}
 
Zuletzt bearbeitet:

Neue Themen


Zurück
Oben