Heim  >  Artikel  >  Java  >  Ausführliche Erläuterung von Wiedereintrittssperren und Lese-/Schreibsperren in der Java-Parallelität

Ausführliche Erläuterung von Wiedereintrittssperren und Lese-/Schreibsperren in der Java-Parallelität

黄舟
黄舟Original
2017-09-26 09:50:061605Durchsuche

In diesem Artikel werden hauptsächlich Wiedereintrittssperren und Lese-/Schreibsperren in der Java-Parallelprogrammierung vorgestellt. Die relevanten Beispielcodes im Artikel sind detailliert und zum Testen verfügbar. Freunde, die sie benötigen, können mehr darüber erfahren.

Wiedereintrittssperre

Die Wiedereintrittssperre ist, wie der Name schon sagt, eine Sperre, die den Wiedereintritt unterstützt, was bedeutet, dass die Sperre das wiederholte Sperren von Ressourcen durch einen Thread unterstützen kann. Wiedereintritt bedeutet, dass jeder Thread die Sperre erneut erwerben kann, ohne nach dem Erwerb der Sperre durch die Sperre blockiert zu werden. Die Implementierung dieser Funktion muss die folgenden zwei Probleme lösen.

1. Der Thread erhält die Sperre erneut. Die Sperre muss feststellen, ob der Thread, der die Sperre erhält, der Thread ist, der die Sperre derzeit belegt. Wenn ja, kann sie erneut erfolgreich erworben werden.

2. Die endgültige Freigabe der Sperre. Der Thread erhält die Sperre n-mal wiederholt, und nachdem er die Sperre zum n-ten Mal aufgehoben hat, können andere Threads die Sperre erwerben. Die endgültige Freigabe der Sperre erfordert, dass die Sperre die Anzahl der wiederholten Erfassungen erhöht. Wenn die Sperre aufgehoben wird, bedeutet dies, dass die Anzahl verringert wird Die Sperre wurde erfolgreich aufgehoben.

Die integrierte Sperre (synchronisieren) und die Sperre (ReentrantLock) in Java sind beide wiedereintrittsfähige

synchronisierte Instanz


package com.home;
public class SynchronizedTest implements Runnable {
  public synchronized void method1() {
    System.out.println("method1获得锁,正常运行!");
    method2();
  }
  public synchronized void method2() {
    System.out.println("method2获得锁,也正常运行!");
  }
  @Override
  public void run() {
    method1();
  }
  public static void main(String[] args) {
    SynchronizedTest st = new SynchronizedTest();
    new Thread(st).start();
    new Thread(st).start();
  }
}

Instanz sperren


package com.home;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest implements Runnable {
  Lock lock = new ReentrantLock();
  public void method1() {
    lock.lock();
    System.out.println("method1获得锁,正常运行!");
    method2();
    lock.unlock();
  }
  public void method2() {
    lock.lock();
    System.out.println("method2获得锁,也正常运行!");
    lock.unlock();
  }
  @Override
  public void run() {
    method1();
  }
  public static void main(String[] args) {
    LockTest lt = new LockTest();
    new Thread(lt).start();
    new Thread(lt).start();
  }
}

Die Endergebnisse beider Beispiele sind wie folgt korrekt:


method1获得锁,正常运行!
method2获得锁,也正常运行!
method1获得锁,正常运行!
method2获得锁,也正常运行!

Die größte Rolle der Wiedereintrittssperre besteht darin, Deadlocks zu vermeiden

Lese-/Schreibsperre

Die Lese-/Schreibsperre verwaltet ein Paar zusammengehöriger Sperren, eine für schreibgeschützte Vorgänge und eine für Schreibvorgänge. Solange kein Schreiber vorhanden ist, kann die Lesesperre von mehreren Lesethreads gleichzeitig gehalten werden. Schreibsperren sind exklusiv.

ReentrantReadWriteLock

Das ReentrantReadWriteLock-Objekt stellt die Methoden readLock() und writeLock() zum Erlangen von Lese- und Schreibsperren bereit.

Die Lesesperre ermöglicht es mehreren Leserthreads, sie gleichzeitig zu halten, während die Schreibsperre nur von höchstens einem Schreibthread gehalten werden kann.

Lesen Anwendungsfälle für Schreibsperren: Die Häufigkeit des Lesens gemeinsamer Daten ist viel größer als die Häufigkeit der Änderung gemeinsamer Daten. In den oben genannten Situationen kann die Verwendung von Lese-/Schreibsperren zur Steuerung des Zugriffs auf gemeinsam genutzte Ressourcen die Parallelitätsleistung verbessern.

Wenn ein Thread Wenn ein Thread bereits eine Lesesperre besitzt, kann er keine Schreibsperre mehr halten, bis die Lesesperre aufgehoben wird.

Sie können die newCondition()-Methode der Schreibsperre aufrufen, um das an die Schreibsperre gebundene Condition-Objekt zu erhalten. Zu diesem Zeitpunkt besteht jedoch kein Unterschied zu einer gewöhnlichen Mutex-Sperre. Der Aufruf der newCondition der Lesesperre()-Methode löst eine Ausnahme aus.

Beispiel


package com.home;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class ReadWrte {
  // 共享数据,可以多个线程读数据,只能有一个线程写数据
  private int data;
  // 创建读写锁
  ReadWriteLock rwLock = new ReentrantReadWriteLock();
  /**
   * 读数据,上读锁
   */
  public void get() {
    // 读锁
    rwLock.readLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + ",Read!");
      Thread.sleep((long) Math.random() * 1000);
      System.out.println(Thread.currentThread().getName() + " 读出的数据为:" +
        this.getData());
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      rwLock.readLock().unlock();
    }
  }
  /**
   * 写数据,上写锁
   *
   * @param data
   */
  public void put(int data) {
    // 写锁
    rwLock.writeLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + ",Write!");
      Thread.sleep((long) Math.random() * 1000);
      this.setData(data);
      System.out.println(Thread.currentThread().getName() + " 写入的数据为:" +
        this.getData());
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      rwLock.writeLock().unlock();
    }
  }
  public int getData() {
    return data;
  }
  public void setData(int data) {
    this.data = data;
  }
}
/**
 * 测试类
 *
 * @author itmyhome
 *
 */
public class ReadWriteLockTest {
  /**
   * @param args
   */
  public static void main(String[] args) {
    // 创建ReadWrte对象
    final ReadWrte rw = new ReadWrte();
    for (int i = 0; i < 10; i++) {
      // 创建并启动10个读线程
      new Thread(new Runnable() {
          @Override
          public void run() {
            rw.get();
          }
        }).start();
      // 创建并启动10个写线程
      new Thread(new Runnable() {
          @Override
          public void run() {
            // 写入一个随机数
            rw.put(new Random().nextInt(8));
          }
        }).start();
    }
  }
}

Ausgabe ist


Thread-0,Read!
Thread-4,Read!
Thread-8,Read!
Thread-12,Read!
Thread-0 读出的数据为:0
Thread-4 读出的数据为:0
Thread-8 读出的数据为:0
Thread-12 读出的数据为:0
Thread-19,Write!
Thread-19 写入的数据为:5
Thread-7,Write!
Thread-7 写入的数据为:7
Thread-3,Write!
Thread-3 写入的数据为:4
Thread-16,Read!
Thread-16 读出的数据为:4
Thread-11,Write!
Thread-11 写入的数据为:0
Thread-15,Write!
Thread-15 写入的数据为:5
Thread-2,Read!
Thread-2 读出的数据为:5
Thread-17,Write!
Thread-17 写入的数据为:2
Thread-6,Read!
Thread-6 读出的数据为:2
Thread-1,Write!
Thread-1 写入的数据为:5
Thread-13,Write!
Thread-13 写入的数据为:4
Thread-9,Write!
Thread-9 写入的数据为:7
Thread-5,Write!
Thread-5 写入的数据为:2
Thread-10,Read!
Thread-10 读出的数据为:2
Thread-18,Read!
Thread-14,Read!
Thread-18 读出的数据为:2
Thread-14 读出的数据为:2

Auf dem Bild können wir sehen, dass mehrere Threads gleichzeitig lesen können, aber nur ein Thread schreiben kann, dh das Schreiben von Daten und das Schreiben von Daten werden gleichzeitig abgeschlossen.

Zusammenfassung

Das obige ist der detaillierte Inhalt vonAusführliche Erläuterung von Wiedereintrittssperren und Lese-/Schreibsperren in der Java-Parallelität. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn