ReentrantLock(可重入的独占锁) 应用
解决多线程竞争
实现多线程的顺序执行
实现多线程等待 / 通知机制
使用范式 1 2 3 4 5 6 lock.lock(); try { }finally { lock.unlock() }
场景 ** 递归 **、调用同类中方法、锁嵌套
抢票 结合 Condition 实现生产者消费者模式 Conditon 有 await()阻塞,signal() 唤醒,等待唤醒机制
机制
生产者会在消息队列满了之后阻塞,生产后唤醒消费者消费
消费者会在消息队列空了之后阻塞,消费后唤醒生产者生产
核心代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 T[]items=new Object [size]; int count=0 ; int putIndex=0 ; int takeIndex=0 ; int size=0 ; Lock lock=new ReentrantLock (); Condition notEmpty=lock.newCondition; Condition notFull=lock.newCondition; public void put (e) { lock.lock(); try { while (count==size){ notFull.await(); } if (++index==size){ index=0 ; } item[index]=e; ++count; notEmpty.signalAll(); }finally { lock.unlock; } } public T take () { lock.lock(); try { while (count==size){ notEmpty.await(); } if (++takeIndex==size){ takeIndex=0 ; } item[takeIndex]=null ; --count; notfull.signalAll(); }finally { lock.unlock; } }
公平锁和非公平锁
公平锁,不可以插队获取锁
非公平锁,可以插队获取锁
Semaphore(信号量) 应用 控制同时访问某资源的线程数量,这也是共享锁,同时可以多个线程使用
场景 限流 实现并发访问量,控制流量
资源池 实现资源池,维护一组有限资源(比如数据库连接池,限定连接对象 50 个)
使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 private static Semaphore sem=new Semaphore (2 ); fun getProductInfo () { try { semaphore.acquire(); }catch (){ }finally { semaphore.release(); } }
CountDownLatch(闭锁) 应用 同步协助,允许线程等待,直到其他线程完成才一起操作
场景
并行任务同步
多任务汇总
资源初始化
实际场景
百米跑步,同时开跑
统一交卷
商品详情页数据汇总
使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 static CountDownLatch begin=new CountDownLatch (1 );static CountDownLatch end=new CountDownLatch (8 ); fun run () { sout(" 准备 " ); begin.await(); sout(" 跑步 " ); sout(" 到达终点 " ); end.countDown(); } fun main () { for (i 0. .8 ){ new Thread .start(); } begin.countDown(); end.await(); sout(" 结束比赛 " ) }
CyclicBarrier 应用 对 CountDownLatch 优化,同 end 方式,但能重复使用
但如果没置零,则会一直阻塞
场景
实际场景
Exchanger 两个线程用于交换数据
场景
Phaser 对 CountDownLatch 和 CyclicBarrier 优化,同 end 方式,但可以控制每个阶段的完成数量,
场景 比如公司团建爬山、吃饭、唱歌
三个阶段中,都可以让线程退出或加入