这是一个锁降级的demo ,请问为什么在50行释放写锁之后 读线程仍然很大几率会被堵塞住呢?

这段demo里就算我释放了写锁,读线程还是很大几率会被堵塞住,只是偶尔会得到执行权。锁降级不是当前线程获得写锁然后获得读锁堵塞住其他写线程再释放写锁吗,那么这段代码里写线程释放锁之后读线程应该立刻得到执行权才对。我这个问题是代码问题还是我的理解有错误呢。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteTest {
    public static void main(String[] args) {
        ReadWriteFac fac = new ReadWriteFac();
        Thread thread = new Thread();
        for (int i = 0; i < 5; i++) {
           Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        fac.get();
                    }
                }
            }, "读线程" + i);
           t1.setPriority(10);
           t1.start();
        }
        for (int i = 0; i < 10; i++) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    fac.plus();
                }
            }, "写线程" + i);
            t1.setPriority(1);
            t1.start();
        }
    }
}

class ReadWriteFac {
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private volatile int i = 0;
    Lock r = lock.readLock();
    Lock w = lock.writeLock();

    public void plus() {
        w.lock();
        System.out.println(Thread.currentThread().getName() + "---获取了写锁");
        try {
            i++;
            System.out.println(Thread.currentThread().getName() + "---将i修改为" + i);
            r.lock();
        } finally {
            w.unlock();//释放写锁  因为上面读锁未被释放 其他写线程无法进入但读线程可以继续
            System.out.println(Thread.currentThread().getName() + "---释放了写锁\r\n\r\n");
            try{
                TimeUnit.SECONDS.sleep(3);
            }catch(Exception e){
            }
            r.unlock();//释放读锁
            System.out.println(Thread.currentThread().getName() + "---释放了读锁");
        }
    }

    public int get() {
        r.lock();
        try {
                if(i!=10){
                    System.out.println(Thread.currentThread().getName() + "获取到了" + i);
                }
            return i;
        }finally {
            r.unlock();
        }
    }
}

这是输出
按理说51行释放写锁之后其他读线程应该得到执行权,现在只是偶尔得到

首先,你理解的没问题,的确是这样,其实问题在于你的线程名称读写名称0-5 是重复了,导致看不到交替获取读锁的现象。

此外,读写锁适用读多写少的场景,而这个测试案例恰好相反,写多读少,导致写锁一释放,就被其他的写线程给抢占了,所以读线程依旧是没有机会获取读锁。可以调小写线程个数,打印时间,就能看到写线程释放写锁休眠期间读线程获取读锁的过程了。

修正第二段循环的 i 的初始值,使得所有线程编号都不相同:

//开启了 10 个写线程
        for (int i = 6; i < 16; i++) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    fac.plus();
                }
            }, "写线程" + i);
            t1.setPriority(1);
            t1.start();
        }

最后再运行就能看到写操作完成后读线程交替获取读锁的过程了:
图片说明