java.util.concurrent 工具包 ( 三 ) ----- ReentrantLock和ReentrantReadWriteLock

java.util.concurrent 工具包 ( 三 )


Lock ( 接口 )

-------基本-------
  • JUC 包中 各种锁的接口
  • 记录着一些锁的基本方法

-------实现类-------
  • ReentrantLock ( 可重入锁 )
  • ReadWriteReentrantLock.WriteLock ( 读写锁中的写锁 )
  • ReadWriteReentrantLock.ReadLock ( 读写锁中的读锁 )
  • StampedLock.ReadLockView
  • StampedLock.WriteLockView

-------方法-------
接口方法作用备注
void lock()获取锁阻塞且不会被中断
void lockInterruptibly() throws InterruptedException获取锁阻塞但是能够被中断
boolean tryLock()尝试获取一下锁不阻塞,返回值是是否抢到了锁
boolean tryLock(long time, TimeUnit unit) throws InterruptedException尝试一段时间获取锁阻塞一段时间,能够被中断
void unlock()返还锁
Condition newCondition()


ReadWriteLock ( 接口 )

-------基本-------
  • 读写锁的统一接口层

-------实现类-------
  • ReadWriteReentrantLock
  • StampedLock.ReadWriteLockView

-------方法-------
API作用备注
Lock readLock()获得读锁
Lock writeLock()获得写锁


ReentrantLock ( 实现类 )

-------基本-------
  • 它是一个显式的可重入的锁
  • 基于AQS实现的
  • 是Lock接口的一个实现类

-------构造方法-------
构造方法作用备注
ReentrantLock()构造一个实例默认是非公平的锁
ReentrantLock(boolean fair)构造一个 公平/不公平 的锁true为公平锁
false为非公平的锁

-------常用API-------
API作用备注
int getHoldCount()查询当前线程保持此锁定的个数, 即调用lock()方法的次数用来查看当前线程重入了多少次锁
int getQueueLength()获得等待锁的线程的数量
int getWaitQueueLength(Condition condition)查询正在等待给定条件的线程有多少
不精准,估计值
如果给定的condition和锁没有关系会抛出异常
或者没有持有锁也会
boolean hasQueuedThread(Thread thread)判断是个线程是否被阻塞
boolean hasQueuedThreads()是否有线程被阻塞
boolean hasWaiters(Condition condition)查询是否有些线程正在等待与此锁有关的给定条件。注意,因为随时可能发生超时中断,所以返回 true 并不保证将来某个 signal 将唤醒线程。此方法主要用于监视系统状态如果给定的condition和锁没有关系会抛出异常
或者没有持有锁也会
boolean isFair()是不是公平的锁
boolean isHeldByCurrentThread()当前线程是否lock在这个锁上
boolean isLocked()是否有线程在lock这个锁上

-------代码示例-------
  1. 基本lock接口的方法测试

    package myConcurrent.s2020_03_28;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    import java.util.stream.IntStream;
    
    public class ReentrantLockExample1 {
        public static void main(String[] args) {
            final Lock lock = new ReentrantLock();
            IntStream.range(0, 5).forEach(
                    i -> new Worker(lock, i + "")
            );
            boolean flag = lock.tryLock();
            if(flag){
                System.out.println("我抢到锁了!");
                lock.unlock();
            }else
                System.out.println("我没有抢到锁!");
        }
    
        public static class Worker extends Thread {
            private final Lock lock;
    
            public Worker(Lock lock, String name) {
                super(name);
                this.lock = lock;
                this.start();
            }
    
            @Override
            public void run() {
    //            while (true) {
    //                if(lock.tryLock())break;
    //            }
    //            System.out.println(Thread.currentThread().getName() + " 抢到了锁");
    //            lock.unlock();
                try {
                    lock.lock();
                    System.out.println(Thread.currentThread().getName() + " 正在工作!");
                    Thread.sleep(1_000);
                } catch (Exception ignore) {
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    
    

  2. 测试重入锁的一些基本方法

    package myConcurrent.s2020_03_28;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ReentrantLockExample2 {
        public static void main(String[] args) throws InterruptedException {
            final ReentrantLock reentrantLock = new ReentrantLock();
            System.out.println("这个锁是不是公平的 : " + reentrantLock.isFair());
            new Thread(
                    () -> myLock(reentrantLock, 10)
            ).start();
    
            mySleep();
    
            //lock了多少次! 就需要unlock多少次
            reentrantLock.lock();
            System.out.println("正确的unlock了");
            reentrantLock.unlock();
    
            //获取 多少个线程正在等待
            Thread thread1 = new Thread(() -> {
                try {
                    reentrantLock.lockInterruptibly();
                    System.out.println("线程1冲冲冲~");
                    mySleep();
                    mySleep();
    
                } catch (InterruptedException e) {
                } finally {
                    if (reentrantLock.isHeldByCurrentThread())
                        reentrantLock.unlock();
                }
            });
            Thread thread2 = new Thread(() -> {
                try {
                    reentrantLock.lockInterruptibly();
                    System.out.println("线程2冲冲冲~");
                    mySleep();
                    mySleep();
    
                } catch (InterruptedException e) {
                } finally {
                    if (reentrantLock.isHeldByCurrentThread())
                        reentrantLock.unlock();
                }
            });
            thread1.start();
            thread2.start();
    
            mySleep();
            System.out.println("<< 正在等待的线程数 : " + reentrantLock.getQueueLength());
            thread1.interrupt();
            thread2.interrupt();
    
            
        }
    
        public static void myLock(final ReentrantLock reentrantLock, int n) {
            if (n == 0) {
            } else {
                reentrantLock.lock();
                System.out.println(">> holdCount : " + reentrantLock.getHoldCount());
                myLock(reentrantLock, n - 1);
                reentrantLock.unlock();
            }
        }
    
        public static void mySleep() throws InterruptedException {
            TimeUnit.SECONDS.sleep(1);
        }
    }
    
    

  3. 测试Condition…使用lock 组合 condition 制作 生产者消费者队列

    package myConcurrent.s2020_03_28;
    
    
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.Random;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    import java.util.stream.IntStream;
    
    public class ReentrantLockExample3 {
        private static final int MAX_QUEUE_SIZE = 20;
    
        private static final ReentrantLock LOCK = new ReentrantLock(true);
        private static final Condition PRO_CONDITION = LOCK.newCondition();      //获得一个condition
        private static final Condition CON_CONDITION = LOCK.newCondition();      //获得一个condition
    
        public static void main(String[] args) throws InterruptedException {
    
            final Queue<Integer> queue = new LinkedList<>();
            final Random random = new Random();
            IntStream.range(0, 5).forEach(i ->
                    new Producer(queue, random)
            );
            IntStream.range(0, 5).forEach(i -> new Consumer(queue));
    
            mySleep();
            mySleep();
    
            new Thread(
                    () -> {
                        while (true){
                            LOCK.lock();
                            System.out.println("====================================");
                            System.out.println("=现在是否是有生产者在等待唤醒 : " + LOCK.hasWaiters(PRO_CONDITION));
                            System.out.println("=现在是否是有消费者在等待唤醒 : " + LOCK.hasWaiters(CON_CONDITION));
                            System.out.println("=消费者等待队列长度 : " + LOCK.getWaitQueueLength(PRO_CONDITION));
                            System.out.println("=生产者等待队列长度 : " + LOCK.getWaitQueueLength(CON_CONDITION));
    
                            System.out.println("====================================");
                            LOCK.unlock();
                            try {
                                mySleep();
                                mySleep();
    
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
            ).start();
    
        }
    
        private static class Producer extends Thread {
            private final Queue<Integer> queue;
            private final Random random;
    
            public Producer(Queue<Integer> queue, Random random) {
                this.queue = queue;
                this.random = random;
                this.start();
            }
    
            @Override
            public void run() {
                while (true) {
                    LOCK.lock();
                    try {
                        while (queue.size() >= MAX_QUEUE_SIZE) {
                            PRO_CONDITION.await();
                        }
                        queue.add(random.nextInt(20));
                        print(queue);
                        mySleep();
    
                        CON_CONDITION.signal();
                    } catch (InterruptedException ignore) {
                        break;
                    } finally {
                        if (LOCK.isHeldByCurrentThread())
                            LOCK.unlock();
                    }
                }
            }
    
            private void print(Queue<Integer> queue) {
                StringBuilder builder = new StringBuilder();
                builder.append("现在生成的线程是 : ")
                        .append(Thread.currentThread().getName())
                        .append(' ');
                for (int num : queue) {
                    builder.append(num).append(',');
                }
                System.out.println(builder.toString());
            }
        }
    
        private static class Consumer extends Thread {
            private final Queue<Integer> queue;
    
            public Consumer(Queue<Integer> queue) {
                this.queue = queue;
                this.start();
            }
    
            @Override
            public void run() {
                while (true) {
                    LOCK.lock();
                    try {
                        while (queue.isEmpty()) {
                            CON_CONDITION.await();
                        }
                        Integer produce = queue.poll();
                        System.out.println(Thread.currentThread().getName() + " 消费掉了 : " + produce);
                        mySleep();
    
                        PRO_CONDITION.signal();
                    } catch (InterruptedException ignore) {
                        break;
                    } finally {
                        if (LOCK.isHeldByCurrentThread())
                            LOCK.unlock();
                    }
                }
            }
        }
    
        private static void mySleep() throws InterruptedException {
            TimeUnit.MILLISECONDS.sleep(100);
        }
    }
    
    


ReentrantReadWriteLock ( 实现类 )

-------基本-------
  • 是ReadWriteLock接口的实现类
  • 内部有一个 读锁 ReadLock ( Lock的实现类 )
  • 内部有一个 写锁 WriteLock ( Lock的实现类 )

-------构造方法-------

同 ReentrantLock 的构造方法


-------常用API-------

除了Lock接口的方法

几乎同 ReentrantLock里的方法一样


-------代码示例-------
  1. 读写分离的Example

    package myConcurrent.s2020_03_28;
    
    import java.util.Random;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    import java.util.stream.IntStream;
    
    public class ReentrantReadWriteLockExample1 {
        private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock(true);
        private static final ReentrantReadWriteLock.ReadLock READ_LOCK = LOCK.readLock();
        private static final ReentrantReadWriteLock.WriteLock WRITE_LOCK = LOCK.writeLock();
    
        public static void main(String[] args) {
            final ShareObject object = new ShareObject();
            IntStream.range(0, 5).forEach(i -> new Reader(object).start());
            IntStream.range(0, 1).forEach(i -> new Writer(object).start());
        }
    
        public static void mySleep() throws InterruptedException {
    //        TimeUnit.SECONDS.sleep(1);
        }
    
        static class ShareObject {
            String shareString = "bbbb";
        }
    
        static class Writer extends Thread {
            private final ShareObject object;
            private final Random random = new Random();
    
            Writer(ShareObject object) {
                this.object = object;
            }
    
            @Override
            public void run() {
                while (true) {
                    WRITE_LOCK.lock();
                    char c = (char) ('a' + random.nextInt(26));
                    StringBuilder builder = new StringBuilder();
                    for (int i = 0; i < 10; i++) builder.append(c);
                    object.shareString = builder.toString();
                    WRITE_LOCK.unlock();
                    try {
                        mySleep();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }
        }
    
        static class Reader extends Thread {
            private final ShareObject object;
    
            Reader(ShareObject object) {
                this.object = object;
            }
    
            @Override
            public void run() {
                while (true) {
                    READ_LOCK.lock();
                    System.out.println(object.shareString);
                    READ_LOCK.unlock();
                    try {
                        mySleep();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
    
    }
    
    



Condition ( 接口 )

-------基本-------
  • condition 由 lock.newCondition() 可以使用
  • 类似 在 synchronized(object) 块中的 object 监视器

-------方法-------
API作用备注
void await() throws InterruptedException类似object.wait(),可以被打断,释放显式锁的方法,加入锁的等待队列中
boolean await(long time, TimeUnit unit) throws InterruptedException等待一个条件在一段时间内是否会发生,不会发生返回false , 发生了返回 true是个阻塞方法
long awaitNanos(long nanosTimeout) throws InterruptedException等待一个条件发生之后, 还剩下多少的时间是个阻塞方法
void awaitUninterruptibly()不会响应中断的等待方法
boolean awaitUntil(Date deadline) throws InterruptedException同第二个方法
void signal()等同于object.notify() 唤醒 在一个条件中等待的一个线程
void signalAll()等同于object.notifyAll() 换新在一个条件中等待的所有线程



感谢观看~

来自一个萌新的日常学习

欢迎大佬来拍砖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值