>Java >java지도 시간 >Java 동시 프로그래밍에서 StampedLock 잠금을 사용하는 방법

Java 동시 프로그래밍에서 StampedLock 잠금을 사용하는 방법

WBOY
WBOY앞으로
2023-04-24 08:01:061372검색

StampedLock:

StampedLock은 동시 패키지 JDK8 버전의 새로운 잠금입니다. 이 잠금은 잠금을 획득하기 위해 일련의 함수를 호출할 때 세 가지 읽기 및 쓰기 제어 모드를 제공합니다. 긴 변수를 스탬프라고 합니다. 이 스탬프는 잠금 상태를 나타냅니다. 잠금을 획득하는 try 일련의 함수는 잠금 획득이 실패할 때 스탬프 값 0을 반환합니다. 잠금 해제 및 잠금 변환 메서드를 호출할 때 잠금 획득 시 반환되는 스탬프 값을 전달해야 합니다. StampedLock是并发包里面JDK8版本新增的一个锁,该锁提供了三种模式的读写控制,当调用获取锁的系列函数时,会返回一个long 型的变量,我们称之为戳记(stamp),这个戳记代表了锁的状态。其中try 系列获取锁的函数,当获取锁失败后会返回为0的stamp值。当调用释放锁和转换锁的方法时需要传入获取锁时返回的stamp值。

StampedLock提供的三种读写模式的锁分别如下:

  • 写锁witeLock: 是一个排它锁或者独占锁,某时只有一个线程可以获取该锁,当一个线程获取该锁后,其他请求读锁和写锁的线程必须等待,这类似于 ReentrantReadWriteLock的写锁(不同的是这里的写锁是不可重入锁):当目前没有线程持有读锁或者写锁时才可以获取到该锁。请求该锁成功后会返回一个stamp变量用来表示该锁的版本,当释放该锁时需要调用unlockWrite方法并传递获取锁日的 stamp 参数。并且它提供了非阻塞的tryWriteLock 方法。

  • 悲观读锁 readLock: 是一个共享锁,在没有线程获取独占写锁的情况下,多个线程可以同时获取该锁。如果已经有线程持有写锁,则其他线程请求获取该读锁会被阻塞,这类似于 ReentrantReadWriteLock 的读锁(不同的是这里的读锁是不可重入锁)。这里说的悲观是指在具体操作数据前其会悲观地认为其他线程可能要对自己操作的数据进行修改,所以需要先对数据加锁,这是在读少写多的情况下的一种考虑。请求该锁成功后会返回一个stamp变量用来表示该锁的版本,当释放该锁时需要调用 unlockRead 方法并传递 stamp 参数。并且它提供了非阻塞的 tryReadLock 方法。

  • 乐观读锁tryOptimisticRead: 它是相对于悲观锁来说的,在操作数据前并没有通过 CAS设置锁的状态,仅仅通过位运算测试。如果当前没有线程持有写锁,则简单地返回一个非0的stamp版本信息。获取该 stamp 后在具体操作数据前还需要调用 validate 方法验证该 stamp 是否已经不可用,也就是看当调用 tryOptimisticRead 返回 stamp后到当前时间期间是否有其他线程持有了写锁,如果是则validate 会返回0否则就可以使用该stamp版本的锁对数据进行操作。由于tryOptimisticRead 并没有使用CAS设置锁状态,所以不需要显式地释放该锁。该锁的一个特点是适用于读多写少的场景,因为获取读锁只是使用位操作进行检验,不涉及CAS操作,所以效率会高很多,但是同时由于没有使用真正的锁,在保证数据一致性上需要复制一份要操作的变量到方法栈,并且在操作数据时可能其他写线程已经修改了数据,而我们操作的是方法栈里面的数据,也就是一个快照,所以最多返回的不是最新的数据,但是一致性还是得到保障的。

StampedLock还支持这三种锁一定条件下进行相互转换。例如long tryConvertToWriteLock(long stamp)期望把stamp 标示的锁升级为写锁,

这个函数会在下面几种情况下返回一个有效的stamp(也就是晋升写锁成功):

  • 当前锁已经是写锁模式了。

  • 前锁处于读锁模式,并且没有其他线程是读锁模式

  • 当前处于乐观读模式,并且当前写锁可用

另外,StampedLock

StampedLock에서 제공하는 세 가지 읽기 및 쓰기 모드 잠금은 다음과 같습니다.

  • 🎜write lock witeLock: 🎜은 배타적 잠금 또는 배타적 잠금입니다. 특정 스레드만이 잠금을 획득할 수 있습니다. 스레드가 잠금을 획득하면 읽기 잠금 및 쓰기 잠금을 요청하는 다른 스레드는 대기해야 합니다. 이는 ReentrantReadWriteLock의 쓰기 잠금과 유사합니다. 여기서 쓰기 잠금은 재진입 잠금이 아니라는 점입니다. ) : 현재 읽기 잠금이나 쓰기 잠금을 보유한 스레드가 없는 경우에만 잠금을 획득할 수 있습니다. 잠금을 성공적으로 요청한 후 잠금 버전을 나타내기 위해 스탬프 변수가 반환됩니다. 잠금이 해제되면 UnlockWrite 메서드를 호출하고 잠금 날짜의 스탬프 매개 변수를 전달해야 합니다. 그리고 비차단 tryWriteLock 메서드를 제공합니다. 🎜
  • 🎜🎜비관적 읽기 잠금 readLock: 🎜는 공유 잠금입니다. 스레드가 배타적 쓰기 잠금을 획득하지 않으면 여러 스레드가 동시에 잠금을 획득할 수 있습니다. 스레드가 이미 쓰기 잠금을 보유하고 있으면 읽기 잠금을 획득하려는 다른 스레드의 요청이 차단됩니다. 이는 ReentrantReadWriteLock의 읽기 잠금과 유사합니다(여기서의 읽기 잠금은 재진입 잠금이 아니라는 차이점이 있습니다). 여기서 언급한 비관론은 데이터를 구체적으로 조작하기 전에 다른 스레드가 자신이 조작하는 데이터를 수정할 수 있다고 비관적으로 믿을 것이므로 먼저 데이터를 잠가야 한다는 의미입니다. 이는 적게 읽고 많이 쓸 때 고려해야 할 사항입니다. 잠금을 성공적으로 요청한 후 잠금 버전을 나타내기 위해 스탬프 변수가 반환됩니다. 잠금이 해제되면 UnlockRead 메서드를 호출하고 스탬프 매개변수를 전달해야 합니다. 그리고 비차단 tryReadLock 메서드를 제공합니다. 🎜
  • 🎜🎜Optimistic 읽기 잠금 tryOptimisticRead: 🎜비관적 잠금과 관련이 있습니다. 잠금 상태는 데이터를 실행하기 전에 CAS를 통해 설정되지 않고 비트 연산을 통해서만 테스트됩니다. 현재 쓰기 잠금을 보유한 스레드가 없으면 0이 아닌 스탬프 버전 정보가 반환됩니다. 스탬프를 얻은 후 데이터를 구체적으로 조작하기 전에 유효성 검사 메서드를 호출하여 스탬프를 더 이상 사용할 수 없는지 확인해야 합니다. 즉, tryOptimisticRead가 스탬프를 반환하는 시점과 현재 시점 사이에 쓰기 잠금을 유지하는 다른 스레드가 있는지 확인해야 합니다. 그렇다면 유효성 검사는 0을 반환합니다. 그렇지 않으면 잠금의 스탬프 버전을 사용하여 데이터를 조작할 수 있습니다. tryOptimisticRead는 CAS를 사용하여 잠금 상태를 설정하지 않으므로 명시적으로 잠금을 해제할 필요가 없습니다. 이 잠금의 한 가지 특징은 읽기가 많고 쓰기가 적은 시나리오에 적합하다는 것입니다. 읽기 잠금을 획득하려면 확인을 위해 비트 작업만 사용하고 CAS 작업은 포함되지 않기 때문에 효율성이 훨씬 높습니다. 동시에 실제 잠금을 사용하지 않으므로 데이터 일관성이 보장되며, 데이터를 연산할 때 다른 쓰기 스레드가 데이터를 수정했을 수 있으므로 연산할 변수를 연산해야 합니다. 스냅샷인 메서드 스택의 데이터이므로 가장 많이 반환되는 데이터는 최신 데이터는 아니지만 일관성은 여전히 ​​보장됩니다. 🎜
🎜StampedLock은 특정 조건에서 이 세 가지 잠금의 상호 변환도 지원합니다. 예를 들어 long tryConvertToWriteLock(긴 스탬프)은 스탬프로 표시된 잠금을 쓰기 잠금으로 업그레이드할 것으로 예상합니다. 🎜🎜🎜이 함수는 다음 상황(즉, 쓰기 잠금)에서 유효한 스탬프를 반환합니다. 승격 성공) :🎜🎜
  • 🎜현재 잠금은 이미 쓰기 잠금 모드입니다. 🎜
  • 🎜이전 잠금은 읽기 잠금 모드이고 다른 스레드는 읽기 잠금 모드에 있지 않습니다.🎜
  • 🎜현재 낙관적 읽기 모드이고 현재 쓰기 잠금은 다음과 같습니다. available🎜
  • 🎜 게다가 StampedLock 의 읽기 및 쓰기 잠금은 비재진입 잠금이므로 잠금을 획득한 후 잠금을 해제하기 전에 작업을 호출하면 안 됩니다. 호출 스레드가 차단되는 것을 방지하기 위해 잠금을 획득합니다. 여러 스레드가 동시에 읽기 잠금과 쓰기 잠금을 획득하려고 시도하는 경우 누가 먼저 잠금을 획득할지에 대한 특정 규칙은 없으며 최선을 다해 무작위로 수행됩니다. 그리고 잠금은 Lock 또는 ReadWriteLock 인터페이스를 직접 구현하지 않고 내부적으로 양방향 차단 대기열을 유지합니다. 🎜🎜다음은 위에서 소개한 개념을 이해하기 위해 JDK8에서 제공하는 2차원 점을 관리하는 예입니다. 🎜
    package LockSupportTest;
    
    import com.sun.org.apache.bcel.internal.generic.BREAKPOINT;
    
    import java.util.concurrent.locks.StampedLock;
    
    public class Point_Class {
        private double x,y;
        private final StampedLock sl = new StampedLock();
        
        void move(double deltaX, double deltaY) {
            long stamp = sl.writeLock();
            try {
                x += deltaX;
                y += deltaY;
            } finally {
                sl.unlockWrite(stamp);
            }
        }
        
        double distanceFromOrin() {
            long stamp = sl.tryOptimisticRead();
            double currentX = x, currentY = y;
            if (!sl.validate(stamp)) {
                stamp = sl.readLock();
                try {
                    currentX = x;
                    currentY = y;
                } finally {
                    sl.unlockRead(stamp);
                }
            }
            return Math.sqrt(currentX*currentX + currentY*currentY);
        }
        
        void moveIfAtOrigin(double newX, double newY) {
            long stamp = sl.readLock();
            try {
                while (x == 0.0 && y == 0.0) {
                    long ws = sl.tryConvertToWriteLock(stamp);
                    if (ws != 0L) {
                        stamp = ws;
                        x = newX;
                        y = newY;
                        break;
                    } else {
                        sl.unlockRead(stamp);
                        stamp = sl.writeLock();
                    }
                }
            } finally {
                        sl.unlock(stamp);
                    }
                }
    }
    🎜위 코드에서 Point 클래스에는 점의 2차원 좌표를 표현하는 데 사용되는 두 개의 멤버 변수(x, y)와 좌표 변수를 연산하는 세 가지 메서드가 있습니다. 또한 작업의 원자성을 보장하기 위해 StampedLock 개체가 인스턴스화됩니다. 🎜

위 내용은 Java 동시 프로그래밍에서 StampedLock 잠금을 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제