>  기사  >  Java  >  Java 동시성의 재진입 잠금 및 읽기-쓰기 잠금에 대한 자세한 설명

Java 동시성의 재진입 잠금 및 읽기-쓰기 잠금에 대한 자세한 설명

黄舟
黄舟원래의
2017-09-26 09:50:061646검색

이 기사에서는 주로 Java 동시 프로그래밍의 재진입 잠금 및 읽기-쓰기 잠금을 소개합니다. 기사의 관련 예제 코드는 상세하고 테스트에 사용할 수 있습니다. 필요한 친구는 더 자세히 알아볼 수 있습니다.

재진입 잠금

재진입 잠금은 이름에서 알 수 있듯이 재진입을 지원하는 잠금입니다. 이는 잠금이 스레드에 의한 리소스의 반복적인 잠금을 지원할 수 있음을 의미합니다. 재진입이란 잠금을 획득한 후 모든 스레드가 잠금에 의해 차단되지 않고 다시 잠금을 획득할 수 있음을 의미합니다.

1. 스레드가 다시 잠금을 획득합니다. 잠금은 잠금을 획득한 스레드가 현재 잠금을 점유하고 있는 스레드인지 식별해야 합니다. 그렇다면 다시 성공적으로 획득할 수 있습니다.

2. 최종 잠금 해제. 스레드는 n번 반복적으로 잠금을 획득하고 n번째 잠금을 해제한 후 다른 스레드가 잠금을 획득할 수 있습니다. 잠금을 최종 해제하려면 잠금을 획득하기 위한 횟수를 늘려야 합니다. 횟수는 현재 잠금이 반복적으로 획득된 횟수를 나타냅니다. 잠금이 해제되면 횟수가 0이 됩니다. 잠금이 성공적으로 해제되었습니다.

Java의 내장 잠금(동기화) 및 잠금(ReentrantLock)은 모두 재진입 가능

동기화 인스턴스


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();
  }
}

잠금 인스턴스


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();
  }
}

예제의 최종 결과 모두 정확하며 결과는 다음과 같습니다.


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

재진입 잠금의 가장 큰 역할은 교착 상태를 방지하는 것입니다

읽기-쓰기 잠금

읽기-쓰기 잠금은 한 쌍의 관련 잠금을 유지합니다. 하나는 읽기 작업 전용이고 다른 하나는 쓰기 작업 전용입니다. 작성기가 없는 한 읽기 잠금은 여러 판독기 스레드에 의해 동시에 유지될 수 있습니다. 쓰기 잠금은 배타적입니다.

Reentrant ReadWriteLock

ReentrantReadWriteLock 객체는 읽기 잠금 및 쓰기 잠금을 획득하기 위한 readLock() 및 writeLock() 메서드를 제공합니다.

읽기 잠금은 여러 판독기 스레드를 동시에 유지하며 쓰기를 허용합니다. 잠금은 최대 하나의 쓰기 스레드에서만 보유할 수 있습니다.

읽기-쓰기 잠금의 사용 사례: 공유 데이터를 읽는 빈도는 공유 데이터를 수정하는 빈도보다 훨씬 큽니다. 공유 리소스에 대한 액세스를 제어하고 동시성 성능을 향상시킬 수 있습니다.

스레드가 이미 쓰기 잠금을 보유하고 있다면 읽기-쓰기 잠금을 보유할 수 있습니다. 반대로 스레드가 이미 읽기 잠금을 보유하고 있다면 읽기 잠금이 해제되면 쓰기 잠금이 더 이상 유지될 수 없습니다.

쓰기 잠금에 바인딩된 Condition 개체를 얻기 위해 쓰기 잠금의 newCondition() 메서드를 호출할 수 있습니다. 차이점은 무엇입니까? 하지만 읽기 잠금의 newCondition() 메서드를 호출하면 예외가 발생합니다.

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();
    }
  }
}

출력은

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

입니다. 여러 스레드가 동시에 읽을 수 있지만 하나의 스레드만 쓸 수 있습니다. 즉, 데이터 쓰기와 데이터 쓰기가 동시에 완료됩니다.

요약

위 내용은 Java 동시성의 재진입 잠금 및 읽기-쓰기 잠금에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.