Java多线程 ReadWriteLock、StampedLock用法

无论是synchronized机制,还是ReentrantLock加锁,实际上只有一个线程可以执行临界区代码。即读写、写读、读读、写写 两个线程之间是相互阻塞的。然而读线程之间是需要并发的,Java使用ReadWriteLock实现多个线程同时读提高并发性能。

1、ReadWriteLock

import java.util.Arrays;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class RWLock {
    public static void main(String[] args) {
        var point = new Pixel();
        Thread t1 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    point.move(i, i);
                }
            }
        };
        t1.start();

        for (int j = 0; j < 10; j++) {
            Thread t = new Thread() {
                @Override
                public void run() {
                    point.getPosition();
                }
            };
            t.start();
        }
    }
}

class Pixel {
    private int[] position = { 0, 0 };
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock writeLock = lock.writeLock();
    private final Lock readLock = lock.readLock();

    public void move(int i, int j) {
        writeLock.lock();
        try {
            this.position[0] = i;
            this.position[1] = j;
        } finally {
            writeLock.unlock();
        }
    }

    public void getPosition() {
        readLock.lock();
        try {
            System.out.println(Arrays.toString(this.position));

        } finally {
            readLock.unlock();
        }
    }
}

ReadWriteLock 的用法:在需要加写锁的地方调用  writeLock.lock(); 在需要加读锁的地方调用 readLock.lock();

ReadWriteLock保证多个线程可以同时获取读锁,但读写,写读,写写线程之间仍然是阻塞的。

2、StampedLock

由于ReadWriteLock在读的过程中不允许写,这是一种悲观的读锁,Java 8引入了新的读写锁 StampedLock,允许读的过程中写入,这是一种乐观的读锁。

class Point {
    private final StampedLock stampedLock = new StampedLock();

    private double x;
    private double y;

    public void move(double x1, double y1) {
        long stamp = stampedLock.writeLock();
        try {
            this.x += x1;
            this.y += y1;
        } finally {
            stampedLock.unlock(stamp);
        }
    }

    public double getDistance() {
        long stamp = stampedLock.tryOptimisticRead();
        double x2 = this.x;
        double y2 = this.y;
        if (stampedLock.validate(stamp)) {
            stamp = stampedLock.readLock();
            try {
                x2 = this.x;
                y2 = this.y;
            } finally {
                stampedLock.unlock(stamp);
            }
        }
        return Math.sqrt(x2 * x2 + y2 * y2);
    }
}

需要注意的是:

1、StampedLock 获取锁的方法会返回一个邮戳(Stamp);

2、释放锁的方法也需要一个邮戳(Stamp);

3、StampedLock是不可重入的;

4、StampedLock有三种访问模式:

  • Reading(读模式):功能和ReentrantReadWriteLock的读锁类似
  • Writing(写模式):功能和ReentrantReadWriteLock的写锁类似
  • Optimistic reading(乐观读模式):这是一种优化的读模式。

5、StampedLock支持读锁和写锁的相互转换;

6、无论写锁还是读锁,都不支持Conditon等待。

 

 

 

 

参考链接:

https://segmentfault.com/a/1190000015808032

https://www.liaoxuefeng.com/wiki/1252599548343744/1309138673991714

 

posted @ 2021-11-16 10:36  恩恩先生  阅读(95)  评论(0编辑  收藏  举报