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这个锁上 |
-------代码示例-------
-
基本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(); } } } }
-
测试重入锁的一些基本方法
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); } }
-
测试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里的方法一样
-------代码示例-------
-
读写分离的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() 换新在一个条件中等待的所有线程 |
感谢观看~
来自一个萌新的日常学习
欢迎大佬来拍砖