Frage

Ich habe eine Java-Klasse, die in einer Multithreading-Anwendung verwendet wird.Ein gleichzeitiger Zugriff ist sehr wahrscheinlich.Mehrere gleichzeitige Lesevorgänge sollten nicht blockiert werden, daher verwende ich eine ReadWrite-Sperre.

class Example {
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private int i;
    private boolean b;

    public int getI() {
      lock.readLock().lock();
      final int tmp = i;
      lock.readLock().unlock(),
      return tmp;
    }

    public void setI( final int i ) {
      lock.writeLock().lock();
      this.i = i;
      lock.writeLock().unlock();
    }

    public boolean getB() {
      lock.readLock().lock();
      final boolean tmp = b;
      lock.readLock().unlock(),
      return tmp;
    }

    public void setB( final boolean b ) {
      lock.writeLock().lock();
      this.b = b;
      lock.writeLock().unlock();
    }
}

Der Einfachheit halber habe ich das weggelassen try...finally Blöcke um die Schlösser herum in diesem Beispiel.

Ich frage mich, ob es notwendig (oder sagen wir empfohlen) ist, Getter und Setter primitiver Typen zu sperren/synchronisieren?Ich weiß, dass Zuweisungs- und Rückgabeoperationen in Java atomar sind.Durch die Verwendung dieser Sperren stelle ich jedoch nicht sicher, dass jeder Accessor den neuesten Wert erhält (entspricht using). volatile)?

Was wäre, wenn die Primitiven es wären double oder long?

War es hilfreich?

Lösung

Es kommt darauf an.

Beachten Sie jedoch, dass Sie Vorgänge normalerweise auf einer gröberen Ebene synchronisieren müssen, zum Beispiel hier:

Example e = ...;

synchronized (e) {
    e.setI(e.getI() + 10);
}

Für solche Szenarien sind Ihre internen Sperren überflüssig.Daher wäre es möglicherweise besser, bei der Verwendung dieser Objekte eine externe Synchronisierung anstelle einer internen Synchronisierung anzuwenden.

Andere Tipps

Sie haben so etwas wie AtomicInteger in Java, das gut mit MultiThreaded Application funktioniert.

Fragen Sie sich, ob diese Klasse als unveränderliche Klasse implementiert werden kann.Es wird einfacher zu handhaben sein und von Natur aus Thread-sicher sein.Sie müssen sich keine Gedanken über Parallelität, Sperren, Synchronisierung usw. machen.

Beispiel einer unveränderlichen Klasse:

final class Example {
    private final int i;
    private final boolean b;

    public Example(int i, boolean b){
        this.i = i ;
        this.b = b;
    }

    public int getI() {
        return i;
    }

    public boolean getB() {
        return b;
    }
}

Ich würde Ihre Anwendung so gestalten, dass Sie keinen gleichzeitigen Zugriff auf einen Rohdatentyp wie diesen haben.Das Hinzufügen einer solchen Sperrung auf niedriger Ebene wird Ihre Anwendung wahrscheinlich so sehr verlangsamen, dass es sich nicht lohnt, Ihre Anwendung mit mehreren Threads zu versehen.

z.B.Angenommen, Sie haben ein System mit 32 Kernen, das perfekt skaliert und 32-mal schneller läuft als auf einem Kern.Allerdings dauert ein Feldzugriff ohne Sperrung 1 ns, mit Sperre 1 us (1000 ns), sodass Ihre Anwendung am Ende etwa 30-mal langsamer sein könnte.(1000 langsamer / 32 schneller) Wenn Sie nur 4 Kerne haben, könnte es hunderte Male langsamer sein und den Zweck von Multi-Threads von vornherein zunichtemachen.MEINER BESCHEIDENEN MEINUNG NACH.

Es ist nicht erforderlich, Getter und Setter primitiver Typen zu sperren/synchronisieren. In den meisten Fällen reicht es aus, sie als flüchtig zu kennzeichnen (außer bei double und long, wie Sie erwähnen).

Wie in einem der vorherigen Beiträge erwähnt, müssen Sie auf Lese- und Aktualisierungssequenzen achten, etwa incrementI(int num), die wahrscheinlich getI() und setI() aufrufen – in diesem Fall könnten Sie ein „synchronisiertes incrementI(int num)'-Methode zu Ihrer Beispielklasse hinzufügen.Die Sperrung erfolgt dann auf einer höheren Ebene, wodurch die Notwendigkeit separater Lese- und Schreibsperren verringert wird und OO-freundlich ist, da Daten und Verhalten zusammen bleiben.Diese Technik ist noch nützlicher, wenn Sie mehrere Felder gleichzeitig lesen/aktualisieren.

Wenn Sie jedoch einfach nur ein Feld nach dem anderen lesen/schreiben/aktualisieren, sind die AtomicXX-Klassen besser geeignet

Sie sollten keine Sperre für primitive Typen, String (sie sind unveränderlich) und Thread-sichere Typen (wie Sammlungen aus dem „concurrent“-Paket) verwenden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top