ReentrantLock类与ReentrantReadWriteLock类

ReentrantLock介绍

1、可重入锁。可重入锁是指一个线程可以多次获取同一把锁,ReentrantLock和Synchronized都是可重入锁,ReentrantLock主要有两个特性,一个是支持公平锁和非公平锁,一个是可重入,依赖于AQS(AbstractQueuedSynchronizer)实现。
2、可中断锁。可中断锁是指线程尝试获取锁的过程是否可以响应终端。synchronized是不可中断锁,而ReentrantLock则提供了中断功能。
3、公平锁与非公平锁。公平所指多个线程同时尝试获取同一把锁时,获取锁的顺序按照线程达到的顺序,而非公平锁则允许线程“插队”。synchronized是非公平锁,而ReentrantLock的默认实现是非公平锁,但是也可以设置为公平锁。

ReentrantLock继承关系图

在这里插入图片描述

ReentrantLock使用示例

public class ReentrantLockDemo {
    private static void testLock(){
        Lock lock = new ReentrantLock();
        lock.lock();
        try{
            for(int i = 0; i<5; i++){
                System.out.println(Thread.currentThread()+"---"+i);
            }
        }catch (Exception e){
            throw e;
        }finally {
            lock.unlock();
        }
    }

    static class ThreadDemo extends Thread{
        @Override
        public void run() {
            testLock();
        }
    }

    public static void main(String[] args) {
        ThreadDemo threadDemo1 = new ThreadDemo();
        ThreadDemo threadDemo2 = new ThreadDemo();
        ThreadDemo threadDemo3 = new ThreadDemo();
        threadDemo1.start();
        threadDemo2.start();
        threadDemo3.start();

    }
运行结果:
Thread[Thread-0,5,main]---0
Thread[Thread-0,5,main]---1
Thread[Thread-0,5,main]---2
Thread[Thread-0,5,main]---3
Thread[Thread-0,5,main]---4
Thread[Thread-2,5,main]---0
Thread[Thread-2,5,main]---1
Thread[Thread-2,5,main]---2
Thread[Thread-2,5,main]---3
Thread[Thread-2,5,main]---4
Thread[Thread-1,5,main]---0
Thread[Thread-1,5,main]---1
Thread[Thread-1,5,main]---2
Thread[Thread-1,5,main]---3
Thread[Thread-1,5,main]---4
}

以上代码是ReentrantLock非公平锁的实现方式,线程获取锁存在随机性。将Lock lock = new ReentrantLock()调整为Lock lock = new ReentrantLock(true)及为公平锁,将会维护一个堵塞队列,按照threadDemo1–>threadDemo2–>threadDemo3的顺序获取锁。

Condition类实现等待通知使用示例

1. notify();notifyAll();唤醒线程是由JVM随机通知的,synchronized加锁相当于整个对象中只有一个Condition对象监视器,所有的线程都注册到它身上,缺少灵活性,
 ReentrantLock加Condition可以实现针对单个Condition对象进行特定线程的唤醒。
public class ReentrantLockDemo {
    static class TestLock{
        Lock lock = new ReentrantLock(true);
        //对象监视器a
        Condition a = lock.newCondition();
        //对象监视器b
        Condition b = lock.newCondition();
  
        private void awaitA(){
            //操作Condition之前必须要先获取锁
            lock.lock();
            try{
                System.out.println("start"+Thread.currentThread()+"--"+System.currentTimeMillis());
                //进入等待状态,释放锁
                a.await();
                System.out.println("end"+Thread.currentThread()+"--"+System.currentTimeMillis());
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //释放锁
                lock.unlock();
            }
        }

        private void awaitB(){
            lock.lock();
            try{
                System.out.println("start"+Thread.currentThread()+"--"+System.currentTimeMillis());
                b.await();
                System.out.println("end"+Thread.currentThread()+"--"+System.currentTimeMillis());
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }

        private void signalA(){
            //操作Condition之前必须要先获取锁
            lock.lock();
            try{
                //唤醒Condition a
                a.signal();
                System.out.println(Thread.currentThread()+"--"+System.currentTimeMillis()+"唤醒a");
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //释放锁
                lock.unlock();
            }
        }

        private void signalB(){
            lock.lock();
            try{
                b.signal();
                System.out.println(Thread.currentThread()+"--"+System.currentTimeMillis()+"唤醒b");
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }

    }
    static class ThreadDemoA extends Thread {
        private TestLock testLock;

        public ThreadDemoA(TestLock testLock) {
            this.testLock = testLock;
        }

        @Override
        public void run() {
            //堵塞ThreadDemoA
            testLock.awaitA();
        }
    }
    static class ThreadDemoB extends Thread {
        private TestLock testLock;

        public ThreadDemoB(TestLock testLock) {
            this.testLock = testLock;
        }

        @Override
        public void run() {
            //堵塞ThreadDemoB
            testLock.awaitB();
        }
    }

    public static void main(String[] args) throws InterruptedException{
        TestLock testLock = new TestLock();
        ThreadDemoA threadDemoA = new ThreadDemoA(testLock);
        threadDemoA.setName("threadDemoA");
        ThreadDemoB threadDemoB = new ThreadDemoB(testLock);
        threadDemoB.setName("threadDemoB");
        threadDemoA.start();
        threadDemoB.start();
        Thread.sleep(2000);
        testLock.signalA();
        Thread.sleep(2000);
        testLock.signalB();
    }
}
运行结果:
startThread[threadDemoA,5,main]--1591258392692
startThread[threadDemoB,5,main]--1591258392701
Thread[main,5,main]--1591258394689唤醒a
endThread[threadDemoA,5,main]--1591258394689
Thread[main,5,main]--1591258396689唤醒b
endThread[threadDemoB,5,main]--1591258396720

ReentrantLock类公平锁与非公平锁

1.公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即FIFO先进先出的顺序。
2.非公平锁是一种锁的抢夺机制,是随机获取锁的,即先来的不一定先得到锁,有些线程
可能一直得不到锁,所以是非公平的。
	//公平锁
	Lock fairLock = new ReentrantLock(true);
	//非公平锁(构造方法不传参,默认创建非公平锁)
	Lock unFairLock = new ReentrantLock(false);

ReentrantLock类常用方法

1.int getHoldCount方法,查询当前线程保持此锁定的个数,ReentrantLock是可重入锁,获得锁之后,调用的内部方法还可以再次获得锁。

public class ReentrantLockDemo {
    private ReentrantLock lock = new ReentrantLock();
    public void serviceMethod1(){
        try {
            lock.lock();
            System.out.println("第一层锁!");
            System.err.println("serviceMethod1保持锁的个数"+lock.getHoldCount());
            //serviceMethod2方法也需要获得锁,需要加锁,
            // 在serviceMethod2方法下,保持的锁个数是2个
            serviceMethod2();
        } finally {
            lock.unlock();
        }
    }

    public void serviceMethod2(){
        try {
            //ReentrantLock是可重入锁,所以serviceMethod2依然可以再次加锁
            //Sychronized也是可重入锁
            lock.lock();
            System.out.println("第二层锁!");
            System.err.println("serviceMethod2保持锁的个数"+lock.getHoldCount());
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        reentrantLockDemo.serviceMethod1();
    }
}
第一层锁!
第二层锁!
serviceMethod1保持锁的个数1
serviceMethod2保持锁的个数2

2.int getQueueLength方法,当前等待获取此锁的线程数。

public class ReentrantLockDemo {
    private static ReentrantLock lock = new ReentrantLock();
    public void serviceMethod1(){
        try {
            lock.lock();
            System.err.println("线程休眠10s,未释放锁");
            //sleep方法执行完不释放锁,wait方法执行完释放锁
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                reentrantLockDemo.serviceMethod1();
            }
        };
        for(int i = 0; i<10; i++){
            //创建10个线程,第1个线程阻塞,其他9个等待获取锁
            Thread thread = new Thread(runnable);
            thread.start();
        }
        Thread.sleep(2000);
        System.err.println("当前等待获取锁的线程数:"+lock.getQueueLength());
    }
}
线程休眠10s,未释放锁
当前等待获取锁的线程数:9

3.int getWaitQueueLength方法是返回等待与此锁定相关条件Condition 的线程估计数,获取Condition条件下的等待线程数

public class ReentrantLockDemo {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();

    public void serviceMethod1(){
        try {
            lock.lock();
            System.err.println("执行await方法,等待唤醒,释放锁");
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                reentrantLockDemo.serviceMethod1();
            }
        };
        for(int i = 0; i<10; i++){
            //创建10个线程去执行await方法
            Thread thread = new Thread(runnable);
            thread.start();
        }
        Thread.sleep(2000);
        try {
            //涉及await等先获取锁再操作
            lock.lock();
            System.err.println("condition监视器下等待唤醒的线程数:"+lock.getWaitQueueLength(condition));
            //全部唤醒
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}
执行await方法,等待唤醒,释放锁
执行await方法,等待唤醒,释放锁
执行await方法,等待唤醒,释放锁
执行await方法,等待唤醒,释放锁
执行await方法,等待唤醒,释放锁
执行await方法,等待唤醒,释放锁
执行await方法,等待唤醒,释放锁
执行await方法,等待唤醒,释放锁
执行await方法,等待唤醒,释放锁
执行await方法,等待唤醒,释放锁
condition监视器下等待唤醒的线程数:10

4.boolean hasQueuedThread(Thread thread)方法,是查询thread线程是否等待获取锁,hasQueuedThreads是查询是否有线程等待获取锁

public class ReentrantLockDemo {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();

    public void serviceMethod1(){
        try {
            lock.lock();
            System.err.println("休眠10s,不释放锁");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                reentrantLockDemo.serviceMethod1();
            }
        };
        Thread threada = new Thread(runnable);
        threada.start();
        threada.sleep(1000);
        Thread threadb = new Thread(runnable);
        threadb.start();
        threadb.sleep(1000);
        System.err.println("threada线程是否正在等到获取锁:"+lock.hasQueuedThread(threada));
        System.err.println("threadb线程是否正在等到获取锁:"+lock.hasQueuedThread(threadb));
        System.err.println("是否有线程正在等到获取锁:"+lock.hasQueuedThreads());
    }
}
休眠10s,不释放锁
threada线程是否正在等到获取锁:false
threadb线程是否正在等到获取锁:true
是否有线程正在等到获取锁:true

5.boolean hasWaiters方法是查询某Condition 条件下是否有线程正在等待唤醒

public class ReentrantLockDemo {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();

    public void serviceMethod1(){
        try {
            lock.lock();
            System.err.println("执行await方法,释放锁");
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                reentrantLockDemo.serviceMethod1();
            }
        };
        Thread threada = new Thread(runnable);
        threada.start();
        threada.sleep(1000);
        Thread threadb = new Thread(runnable);
        threadb.start();
        threadb.sleep(1000);
        try {
            lock.lock();
            System.err.println("condition监视器下是否有线程正在等待唤醒:"+lock.hasWaiters(condition));
            System.err.println("condition监视器下正在等待唤醒线程数:"+lock.getWaitQueueLength(condition));
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}
执行await方法,释放锁
执行await方法,释放锁
condition监视器下是否有线程正在等待唤醒:true
condition监视器下正在等待唤醒线程数:2

6.boolean isFair方法是判断是不是公平锁。默认状态创建的锁都是非公平锁
7.boolean isHeldByCurrentThread方法查询当前是否获取该锁(保持此锁定),boolean isLocked方法查询此锁是否被获取,是否被任意线程获取了此锁,保持此锁定

public class ReentrantLockDemo {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();

    public void serviceMethod1(){
        try {
            lock.lock();
            System.err.println("执行serviceMethod1方法,当前线程是否已获取锁:"+lock.isHeldByCurrentThread());
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void serviceMethod2(){
        System.err.println("执行serviceMethod2方法,当前线程是否已获取锁:"+lock.isHeldByCurrentThread());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                reentrantLockDemo.serviceMethod1();
            }
        };
        Thread threada = new Thread(
            new Runnable() {
                @Override
                public void run() {
                    reentrantLockDemo.serviceMethod1();
                }
            }
        );
        threada.start();
        threada.sleep(1000);
        Thread threadb = new Thread(
            new Runnable() {
                @Override
                public void run() {
                    reentrantLockDemo.serviceMethod2();
                }
            }
        );
        threadb.start();
        threadb.sleep(1000);
        System.out.println("lock锁是否被线程获取:"+lock.isLocked());
    }
}
执行serviceMethod1方法,当前线程是否已获取锁:true
执行serviceMethod2方法,当前线程是否已获取锁:false
lock锁是否被线程获取:true

8.void lockInterruptibly方法是获取锁,如果当前线程未被中断(更改中断标识)则持续等待获取锁,如果当前线程被中断则抛异常。
void lock方法是获取锁,被中断也持续获取锁。

public class ReentrantLockDemo {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();

    public void serviceMethod1(String threadName){
        try{
            System.err.println(threadName+"线程尝试获取锁:");
            lock.lockInterruptibly();//结果如【结果1】所示
            //lock.lock();//结果如【结果2】所示
            System.err.println(threadName+"线程已获取锁:");
            for(int i = 0; i < Integer.MAX_VALUE/100;i++){
                continue;
            }
            System.err.println(threadName+"线程已释放锁:");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        Thread threada = new Thread(
            new Runnable() {
                @Override
                public void run() {
                    reentrantLockDemo.serviceMethod1("threada");
                }
            }
        );
        threada.start();
        threada.sleep(1000);
        Thread threadb = new Thread(
            new Runnable() {
                @Override
                public void run() {
                    reentrantLockDemo.serviceMethod1("threadb");
                }
            }
        );
        threadb.start();
        //尝试获取锁过程中将线程标记中断标识,线程抛异常
        threadb.interrupt();
    }
}
结果1:
threada线程尝试获取锁:
threada线程已获取锁:
threada线程已释放锁:
threadb线程尝试获取锁:
java.lang.InterruptedException
	at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1261)
	at java.base/java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:317)
	at com.example.demo.ReentrantLockDemo.serviceMethod1(ReentrantLockDemo.java:13)
	at com.example.demo.ReentrantLockDemo$2.run(ReentrantLockDemo.java:43)
	at java.base/java.lang.Thread.run(Thread.java:834)

结果2:
threada线程尝试获取锁:
threada线程已获取锁:
threada线程已释放锁:
threadb线程尝试获取锁:
threadb线程已获取锁:
threadb线程已释放锁:

9.boolean tryLock方法在调用时,如果锁未被其他线程保持,则获取锁,返回true;否则不获取锁,返回false。演示该方法
boolean tryLock(long timeout,TimeUnit unit)方法是在给定时间内,持续尝试获取锁,如果锁未被其他线程保持,且当前线程未被中断,则获取锁。不演示该方法

public class ReentrantLockDemo {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();

    public void serviceMethod1(){
        try{
            System.err.println(Thread.currentThread().getName()+"线程尝试获取锁:");
            //尝试获取锁,获取成功返回true
            if(lock.tryLock()){
                System.err.println(Thread.currentThread().getName()+"线程已获取锁:");
            }else{
                System.err.println(Thread.currentThread().getName()+"线程未获取锁:");
            }
            System.err.println(Thread.currentThread().getName()+"线程已结束:");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //如果当前线程持有锁,则释放
            if(lock.isHeldByCurrentThread()){
                lock.unlock();
                System.err.println(Thread.currentThread().getName()+"线程已释放锁:");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        Thread threada = new Thread(
            new Runnable() {
                @Override
                public void run() {
                    reentrantLockDemo.serviceMethod1();
                }
            }
        );
        threada.setName("threada");
        threada.start();
        Thread threadb = new Thread(
            new Runnable() {
                @Override
                public void run() {
                    reentrantLockDemo.serviceMethod1();
                }
            }
        );
        threadb.setName("threadb");
        threadb.start();
    }
}
threada线程尝试获取锁:
threadb线程尝试获取锁:
threada线程已获取锁:
threadb线程未获取锁:
threada线程已结束:
threadb线程已结束:
threada线程已释放锁:

10.void awaitUninterruptibly()方法:线程在调用condition.await()后处于await状态,此时调用thread.interrupt()会报错,但是使用condition.awaitUninterruptibly()后,调用thread.interrupt()则不会报错。

public class ReentrantLockDemo {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();

    public void serviceMethod1(){
        try{
            if(lock.tryLock()){
                System.err.println(Thread.currentThread().getName()+"线程已获取锁,执行await方法。");
                condition.awaitUninterruptibly();
                System.err.println(Thread.currentThread().getName()+"线程await方法结束。");
            }else{
                System.err.println(Thread.currentThread().getName()+"线程未获取锁:");
            }
            System.err.println(Thread.currentThread().getName()+"线程已结束:");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //如果当前线程持有锁,则释放
            if(lock.isHeldByCurrentThread()){
                lock.unlock();
                System.err.println(Thread.currentThread().getName()+"线程已释放锁:");
            }
        }
    }

    public void serviceMethod2(){
        try{
            if(lock.tryLock()){
                System.err.println(Thread.currentThread().getName()+"线程已获取锁,执行signalAll方法。");
                condition.signalAll();
                System.err.println(Thread.currentThread().getName()+"线程signalAll方法结束。");
            }else{
                System.err.println(Thread.currentThread().getName()+"线程未获取锁:");
            }
            System.err.println(Thread.currentThread().getName()+"线程已结束:");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //如果当前线程持有锁,则释放
            if(lock.isHeldByCurrentThread()){
                lock.unlock();
                System.err.println(Thread.currentThread().getName()+"线程已释放锁:");
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        Thread threada = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        reentrantLockDemo.serviceMethod1();
                    }
                }
        );
        threada.setName("threada");
        threada.start();
        Thread.sleep(3000);
        threada.interrupt();
        Thread.sleep(3000);
        reentrantLockDemo.serviceMethod2();
    }
}
threada线程已获取锁,执行await方法。
main线程已获取锁,执行signalAll方法。
main线程signalAll方法结束。
main线程已结束:
main线程已释放锁:
threada线程await方法结束。
threada线程已结束:
threada线程已释放锁:

11.boolean awaitUntil(Date deadline)方法,是在deadline时间到期后,自动唤醒,不会一直等待,await会一直等待,直到唤醒。

public class ReentrantLockDemo {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();
    public void serviceMethod1(){
        try{
            if(lock.tryLock()){
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                System.err.println(Thread.currentThread().getName()+"线程已获取锁,执行await方法,时间:"+calendar.getTime());
                calendar.add(Calendar.SECOND,10);
                condition.awaitUntil(calendar.getTime());
                System.err.println(Thread.currentThread().getName()+"线程await方法结束,时间:"+new Date());
            }else{
                System.err.println(Thread.currentThread().getName()+"线程未获取锁:");
            }
            System.err.println(Thread.currentThread().getName()+"线程已结束:");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //如果当前线程持有锁,则释放
            if(lock.isHeldByCurrentThread()){
                lock.unlock();
                System.err.println(Thread.currentThread().getName()+"线程已释放锁:");
            }
        }
    }

    public void serviceMethod2(){
        try{
            if(lock.tryLock()){
                System.err.println(Thread.currentThread().getName()+"线程已获取锁,执行signalAll方法。");
                condition.signalAll();
                System.err.println(Thread.currentThread().getName()+"线程signalAll方法结束,时间:"+new Date());
            }else{
                System.err.println(Thread.currentThread().getName()+"线程未获取锁:");
            }
            System.err.println(Thread.currentThread().getName()+"线程已结束:");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //如果当前线程持有锁,则释放
            if(lock.isHeldByCurrentThread()){
                lock.unlock();
                System.err.println(Thread.currentThread().getName()+"线程已释放锁:");
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        Thread threada = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        reentrantLockDemo.serviceMethod1();
                    }
                }
        );
        threada.setName("threada");
        threada.start();
        Thread.sleep(3000);
        reentrantLockDemo.serviceMethod2();
    }
}
threada线程已获取锁,执行await方法,时间:Sun Jun 28 15:23:19 CST 2020
main线程已获取锁,执行signalAll方法。
main线程signalAll方法结束,时间:Sun Jun 28 15:23:22 CST 2020
main线程已结束:
threada线程await方法结束,时间:Sun Jun 28 15:23:22 CST 2020
threada线程已结束:
threada线程已释放锁:
main线程已释放锁:

ReentrantReadWriteLock类

ReentrantLock类具有完全排他的效果,效率非常慢,ReentrantReadWriteLock提供了读写锁,一个读锁(共享锁),一个写锁(排他锁),多个读锁之间不互斥,多个写锁之间互斥,读锁与写锁之间互斥。

1.读读共享:一个线程获取了读锁,另一个线程可以继续同时获取此读锁
2.写写互斥:一个线程获取了写锁,一定要释放之后其他线程才能获取此写锁。
3.写读互斥/读写互斥:一个线程获取了读锁,未释放之前不能获取此写锁,或者一个线程获取写锁之后,未释放其他线程不能获取此读锁

示例读写互斥:

public class ReentrantLockDemo {
    //声明读写锁
    private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void serviceMethod1() {
        try {
            System.err.println(Thread.currentThread().getName() + "线程尝试获取读锁:" + new Date());
            //获取读锁,进而加锁
            lock.readLock().lock();
            System.err.println(Thread.currentThread().getName() + "线程已获取读锁:" + new Date());
            //休眠3s不释放锁
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //获取读锁,同时释放锁
            lock.readLock().unlock();
            System.err.println(Thread.currentThread().getName() + "线程已释放读锁:" + new Date());
        }
    }

    public void serviceMethod2() {
            try {
                System.err.println(Thread.currentThread().getName() + "线程尝试获取写锁:" + new Date());
                //获取写锁,进而加锁
                lock.writeLock().lock();
                System.err.println(Thread.currentThread().getName() + "线程已获取写锁:" + new Date());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //获取写锁,同时释放锁
                lock.writeLock().unlock();
                System.err.println(Thread.currentThread().getName() + "线程已释放读锁:" + new Date());
            }
    }


    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        Thread threada = new Thread(
            new Runnable() {
                @Override
                public void run() {
                    reentrantLockDemo.serviceMethod1();
                }
            }
        );
        threada.setName("threada");
        threada.start();
        Thread.sleep(1000);
        Thread threadb = new Thread(
            new Runnable() {
                @Override
                public void run() {
                    reentrantLockDemo.serviceMethod2();
                }
            }
        );
        threadb.setName("threadb");
        threadb.start();
    }
}
threada线程尝试获取读锁:Sun Jun 28 23:55:59 CST 2020
threada线程已获取读锁:Sun Jun 28 23:55:59 CST 2020
threadb线程尝试获取写锁:Sun Jun 28 23:56:00 CST 2020
threada线程已释放读锁:Sun Jun 28 23:56:02 CST 2020
//只有在释放读锁之后,才能获取写锁,读写/写读互斥
threadb线程已获取写锁:Sun Jun 28 23:56:02 CST 2020
threadb线程已释放读锁:Sun Jun 28 23:56:02 CST 2020

总结

Lock对象可以将synchronized关键字代替,其特有的属性是synchronized关键字不具备的,Lock对象是synchronized关键字的进阶,在jdk中并发包中大量类都是使用的Loc接口作为处理同步的方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是使用Java编写的ReentrantLock和ReentrantReadWriteLock的代码示例: ReentrantLock示例: ```java import java.util.concurrent.locks.ReentrantLock; public class Counter { private int count = 0; private ReentrantLock lock = new ReentrantLock(); public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } public void decrement() { lock.lock(); try { count--; } finally { lock.unlock(); } } public int getCount() { return count; } } ``` ReentrantReadWriteLock示例: ```java import java.util.concurrent.locks.ReentrantReadWriteLock; public class Cache { private Object data = null; private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public Object getData() { lock.readLock().lock(); try { return data; } finally { lock.readLock().unlock(); } } public void setData(Object data) { lock.writeLock().lock(); try { this.data = data; } finally { lock.writeLock().unlock(); } } } ``` 在这些示例中,ReentrantLock和ReentrantReadWriteLock都被用于控制共享资源的访问。使用lock()方法获取锁,使用unlock()方法释放锁。在ReentrantReadWriteLock示例中,readLock()和writeLock()方法被用于获取读锁和写锁,以控制对共享数据的读和写访问。 ### 回答2: ReentrantLock(可重入锁)和ReentrantReadWriteLock(可重入读写锁)是Java并发包中提供的两种锁机制。它们都是可重入锁,意味着同一个线程可以多次获取同一个锁。 首先,我们来看一下ReentrantLock的代码例子。在下面的示例中,有两个线程分别尝试获取同一把锁,并对共享资源进行操作。 ```java import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockExample { private static final ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) { Thread thread1 = new Thread(() -> { lock.lock(); try { // 对共享资源进行操作 System.out.println("Thread 1 is accessing the shared resource."); } finally { lock.unlock(); } }); Thread thread2 = new Thread(() -> { lock.lock(); try { // 对共享资源进行操作 System.out.println("Thread 2 is accessing the shared resource."); } finally { lock.unlock(); } }); thread1.start(); thread2.start(); } } ``` 上述代码中,两个线程分别通过lock()方法获取锁,并在finally块中使用unlock()方法释放锁。这就确保了同一时间只能有一个线程访问共享资源。 接下来,我们来看一下ReentrantReadWriteLock的代码例子。与ReentrantLock不同,ReentrantReadWriteLock可以支持多个读线程同时访问共享资源,但只允许一个写线程进行写操作。 ```java import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReentrantReadWriteLockExample { private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private static final ReentrantReadWriteLock.ReadLock readLock = lock.readLock(); private static final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock(); private static int sharedResource = 0; public static void main(String[] args) { Thread reader1 = new Thread(() -> { readLock.lock(); try { // 读取共享资源 System.out.println("Reader 1 is reading the value: " + sharedResource); } finally { readLock.unlock(); } }); Thread reader2 = new Thread(() -> { readLock.lock(); try { // 读取共享资源 System.out.println("Reader 2 is reading the value: " + sharedResource); } finally { readLock.unlock(); } }); Thread writer = new Thread(() -> { writeLock.lock(); try { // 修改共享资源 sharedResource = 100; System.out.println("Writer is updating the value to: " + sharedResource); } finally { writeLock.unlock(); } }); reader1.start(); reader2.start(); writer.start(); } } ``` 在上述代码中,我们使用了readLock()和writeLock()方法来获取读锁和写锁,然后通过lock()方法进行加锁,通过unlock()方法进行解锁。这样保证了在写操作时,不允许其他线程同时进行读或写操作。 以上是ReentrantLock和ReentrantReadWriteLock的简单代码例子,它们在多线程并发操作中提供了可靠的锁机制,确保数据的安全性和一致性。 ### 回答3: ReentrantLock和ReentrantReadWriteLockJava.util.concurrent包中的两个线程同步工具。它们都实现了Lock接口,可以用于对共享资源进行线程安全的访问。 首先,我们来看一下ReentrantLock的代码示例: ```java import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockExample { private ReentrantLock lock = new ReentrantLock(); public void printMessage(String message) { lock.lock(); try { // 访问共享资源 System.out.println(message); } finally { lock.unlock(); // 释放锁 } } } ``` 在上面的示例中,我们创建了一个ReentrantLock对象lock,并将它用于保护printMessage方法中的临界区。lock.lock()用于获取锁,如果锁已被其他线程占用,则当前线程等待。然后在try块中访问共享资源,最后在finally块中使用lock.unlock()来释放锁。 接下来,我们看一下ReentrantReadWriteLock的代码示例: ```java import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReentrantReadWriteLockExample { private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); private String data = "Shared data"; public String readData() { rwLock.readLock().lock(); try { // 读取共享数据 return data; } finally { rwLock.readLock().unlock(); // 释放读锁 } } public void writeData(String input) { rwLock.writeLock().lock(); try { // 更新共享数据 data = input; } finally { rwLock.writeLock().unlock(); // 释放写锁 } } } ``` 在上述示例中,我们创建了一个ReentrantReadWriteLock对象rwLock,并将它用于保护readData和writeData方法中的临界区。rwLock.readLock()用于获取读锁,rwLock.writeLock()用于获取写锁。多个线程可以同时获取读锁,但只有一个线程可以获取写锁。除非有线程持有写锁,否则其他线程可以同时获取读锁。在读操作中,我们使用读锁保护共享数据的只读访问,而在写操作中,我们使用写锁保护共享数据的更新。 以上是ReentrantLock和ReentrantReadWriteLock的简单代码示例,它们可以帮助我们在多线程环境中实现资源的安全访问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值