Wenn ich eine Klasse, die zwei Methoden hat sagen setA
und setB
die synchronized
haben, aber sie sind auf dem gleichen Objekt nicht synchronisiert ist, wie kann ich es sperren, so dass, wenn es zwei Instanzen der Klasse waren, Methoden setA
und setB
nicht passieren kann, gleichzeitig?Wenn ich zwei Methoden habe, die nicht gleichzeitig in einer Klasse in separaten Threads passieren können, wie kann ich sie sperren?
Antwort
Kurz gesagt, können Sie einen synchronized (lockObj) {...}
Block im Körper beider Methoden verwenden, und verwenden Sie die gleiche lockObj
Instanz.
class MyClass {
private final Object lock;
public MyClass(Object lock) {
this.lock = lock;
}
public void setA() {
synchronized (lock) {
//...
}
}
public void setB() {
synchronized (lock) {
//...
}
}
}
Ein paar Dinge zu beachten:
- Das Schloss muss nicht statisch sein. Es hängt von Ihrer Implementierung ab, wie Sie es bereitstellen. Aber jede
MyClass
Instanz muss die selbe Sperrinstanz verwenden, wenn sie verhindern wollen, dass Threads ihre Blöcke gleichzeitig ausführen. - In diesem Fall können Sie keine synchronisierten Methoden verwenden, da jede nicht statische
synchronized
-Methode ihre Methode auf dem Monitor dieser Instanz verwendet. Wenn Sie auf andere Instanzmitglieder zugreifen möchten, können Sie auch die Methodenstatic synchronized
nicht verwenden.
Sie können weiterhin für ein anderes Objekt innerhalb der von Ihnen erstellten Klasse synchronisieren.
Object lock = new Object();
Dann synchronisieren Sie einfach auf das Schloss Objekt.
Wenn Sie ein bisschen mehr in es hinein bekommen möchten, können Sie die Bibliotheken util.concurrency verwenden. Auschecken Semaphore oder Latches, hängt davon ab, was Sie mit Ihrem SetA tun und setB
Synchronisieren Sie sie auf eine einzige, statische Referenz. A private static final Object lock = new Object()
wird tun, wie nur TheClass.class.
Dies bedeutet auch, dass keine zwei Threads gleichzeitig setA aufrufen können, auch wenn niemand setB aufruft. Wenn das nicht akzeptabel ist, können Sie eine (statische) Lese-/Schreibsperre für feineren Zugriff verwenden. setA verwendet die Lesesperre und setB die Schreibsperre. Das bedeutet, dass eine beliebige Anzahl von Threads setA aufrufen kann, aber nur eine kann setB aufrufen. Sie wahrscheinlich nicht wollen das Gegenteil, auch wahr zu sein, denn das ist anfällig für Deadlocking.
Mehrere Möglichkeiten.
1) Sie können die Methoden synchronisieren: public synchronized void setA()
tun, das bedeutet, dass nur ein Thread die Methode zu einem Zeitpunkt (gut und schlecht eingeben)
2) Eine bessere Lösung, die ein ReentrantLock
zu verwenden wäre:
ReentrantLock lock = new ReentrantLock();
void public void setA() {
lock.lock();
try {
//Do Something
}
finally {
lock.unlock();
}
}
Es gibt auch andere Möglichkeiten. können Sie die Java-Tutorial auf Parallelität prüfen: https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
Eine andere anständige Posting: http://winterbe.com/posts/2015/04/30/java8-concurrency-tutorial-synchronized-locks-examples/
Viel Glück!
Erstellen Sie ein statisches Objekt und synchronisieren Sie es. –
Die Frage ist ein bisschen mehrdeutig. Wenn Sie obj1 und obj2 haben, wollen Sie die Aufrufe 'obj1.setA()', um 'obj2.setA()' zu blockieren oder nur 'obj1.setB()' zu blockieren? – Gray