为什么80%的码农都做不了架构师?>>>   

这里举一个栗子,我们对一个资源进行加锁,可是又要进行细粒度的控制,该如何实现呢?

比如我们开了了个餐馆。餐馆有一个厨房,服务员可以通知厨房进行做菜,当前冰箱里有菜时,厨房就会开始做菜,冰箱里没菜则会等待。

/*** Created by Anur IjuoKaruKas on 6/28/2018*/
@SuppressWarnings("Duplicates")
public class Restaurant {private final Lock kitchen = new ReentrantLock();private ConcurrentLinkedDeque<String> meetFridge = new ConcurrentLinkedDeque<>();// 肉冰箱public Runnable cockMeet() {return new Runnable() {@Overridepublic void run() {synchronized (kitchen) {System.out.println("通知厨房做肉");if (meetFridge.isEmpty()) {try {System.out.println("冰箱没有肉了,等待冰箱有肉");kitchen.wait();} catch (InterruptedException e) {e.printStackTrace();}}String meetNeedToCock = meetFridge.getFirst();System.out.println("正在炒" + meetNeedToCock);}}};}public Runnable buySomething() {return new Runnable() {@Overridepublic void run() {synchronized (kitchen) {System.out.println("进货了");meetFridge.addLast("牛肉");kitchen.notify();}}};}public static void main(String[] args) throws InterruptedException {ExecutorService executorService = Executors.newFixedThreadPool(10);Restaurant restaurant = new Restaurant();executorService.execute(restaurant.cockMeet());executorService.execute(restaurant.cockMeet());Thread.sleep(1000);executorService.execute(restaurant.buySomething());Thread.sleep(1000);executorService.execute(restaurant.buySomething());Thread.sleep(1000);executorService.execute(restaurant.buySomething());executorService.execute(restaurant.cockMeet());}
}

运行一下main方法,可以得到以下输出:

通知厨房做肉
冰箱没有肉了,等待冰箱有肉
通知厨房做肉
冰箱没有肉了,等待冰箱有肉
进货了
正在炒牛肉
进货了
正在炒牛肉
进货了
通知厨房做肉
正在炒牛肉

到这里是没有什么问题的。

进来了一个新需求,一个刚好可以用上Condition的新需求

现在我们既需要做肉,也需要做菜。 也就是说: 1、服务员通知了厨房,需要做一个肉和一个菜。这个时候厨房正好没库存,厨房进行了等待。 2、这时候某人去菜市场买了菜回来,厨房开始做菜。 3、过了一段时间 4、某人去菜市场买了肉回来,厨房开始做肉。

这样的一个需求,当然用其他方式实现也是可以的,但如果使用 Condition来实现,它将变得异常简单。
/*** Created by Anur IjuoKaruKas on 6/28/2018*/
@SuppressWarnings("Duplicates")
public class Restaurant {private final Lock kitchen = new ReentrantLock();private final Condition waitMeet = kitchen.newCondition();private final Condition waitVege = kitchen.newCondition();private ConcurrentLinkedDeque<String> meetFridge = new ConcurrentLinkedDeque<>();// 肉冰箱private ConcurrentLinkedDeque<String> vegeFridge = new ConcurrentLinkedDeque<>();// 菜冰箱public Runnable cockMeet() {return new Runnable() {@Overridepublic void run() {kitchen.lock();try {System.out.println("通知厨房做肉");if (meetFridge.isEmpty()) {try {System.out.println("冰箱没有肉了,等待冰箱有肉");waitMeet.await();   // 直接调用condition的wait方法} catch (InterruptedException e) {e.printStackTrace();}}String meetNeedToCock = meetFridge.getFirst();System.out.println("正在炒" + meetNeedToCock);} catch (Exception e) {e.printStackTrace();} finally {kitchen.unlock();}}};}public Runnable cockVege() {return new Runnable() {@Overridepublic void run() {kitchen.lock();try {System.out.println("通知厨房做菜");if (vegeFridge.isEmpty()) {try {System.out.println("冰箱没有菜了,等待冰箱有菜");waitVege.await();   // 直接调用condition的wait方法} catch (InterruptedException e) {e.printStackTrace();}}String meetNeedToCock = vegeFridge.getFirst();System.out.println("正在炒" + meetNeedToCock);} catch (Exception e) {e.printStackTrace();} finally {kitchen.unlock();}}};}public Runnable buySomething() {return new Runnable() {@Overridepublic void run() {kitchen.lock();try {Random random = new Random();if (random.nextBoolean()) {System.out.println("肉进货了");meetFridge.addLast("牛肉");waitMeet.signal();} else {System.out.println("菜进货了");vegeFridge.addLast("苦瓜");waitVege.signal();}} catch (Exception e) {e.printStackTrace();} finally {kitchen.unlock();}}};}public static void main(String[] args) throws InterruptedException {ExecutorService executorService = Executors.newFixedThreadPool(10);Restaurant restaurant = new Restaurant();executorService.execute(restaurant.cockMeet());executorService.execute(restaurant.cockVege());executorService.execute(restaurant.buySomething());}
}

最后输出:

通知厨房做肉
冰箱没有肉了,等待冰箱有肉
通知厨房做菜
冰箱没有菜了,等待冰箱有菜
肉进货了
正在炒牛肉

可见我们可以针对情况对不同的行为进行通知,这就是condition的力量。

提高篇

这里就不瞎扯场景了,直接上代码。

这是仿kafka BufferPool的一种思路,(当然没kafka实现的那么复杂),它的思路是使用一个队列来管理等待的线程。 每次线程进来sout(),都进行等待 满足一定的条件时,mission()会通知队头的一个线程进行操作。

/*** Created by Anur IjuoKaruKas on 6/25/2018*/
public class Task {private Deque<Condition> waiters = new ArrayDeque<>();private Lock lock = new ReentrantLock();private Integer count = 0;private void sout(String str) {this.lock.lock();try {System.out.println("sout " + str + " get the lock");Condition condition = this.lock.newCondition();waiters.addLast(condition);condition.await();Condition conditionFromWaiters = waiters.removeFirst();if (conditionFromWaiters != condition) {System.out.println("???????");}System.out.println("Test Task: " + str);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}private void mission() {this.lock.lock();try {System.out.println("mission get the lock");while (count < 10) {count++;}Condition condition = waiters.peekFirst();if (condition != null) {condition.signal();}count = 0;} finally {lock.unlock();}}public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(10);final Task task = new Task();for (int i = 0; i < 1000000; i++) {final int finalI = i;executorService.execute(new Runnable() {@Overridepublic void run() {task.sout(finalI + "");}});executorService.execute(new Runnable() {@Overridepublic void run() {task.mission();}});}}
}

转载于:https://my.oschina.net/anur/blog/2051172

细粒度的线程控制?使用Lock Condition~相关推荐

  1. 23.多线程(进程的概述和多进程的意义,线程的概述和多线程的意义,JVM运行原理以及JVM启动的线程探讨,实现多线程 线程调度,线程控制,Lock锁,死锁现象)

    1.进程概述及多进程的意义 1.线程和进程     要想说线程,首先必须得聊聊进程,因为线程是依赖于进程存在的. 2.进程概述     什么是进程呢?通过任务管理器我们就可以看到进程的存在.      ...

  2. NO11 java5的线程锁技术(Lock Condition)

    转载于:https://www.cnblogs.com/royi123/archive/2013/06/07/3123127.html

  3. 线程高级篇-Lock锁和Condition条件

    浅谈Synchronized: synchronized是Java的一个关键字,也就是Java语言内置的特性,如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,执行代码块时,其 ...

  4. Java20-day11【实现多线程(进程、线程-调度-控制-生命周期)、线程同步(同步代码块、线程安全、Lock)、生产者消费者(模式概述、案例)】

    视频+资料[链接:https://pan.baidu.com/s/1MdFNUADVSFf-lVw3SJRvtg   提取码:zjxs] Java基础--学习笔记(零起点打开java世界的大门)--博 ...

  5. lock 线程 java_JAVA多线程-基础Lock Condition 并发集合

    跟上一篇文章比较,这次改进了之前的代码,使用了Lock Condition 和并发集合.代码量减了一些,并且更加容易读了. 这篇代码是上一篇的改进版,逻辑在前篇有说明,以防大家看不到,我再重现贴一遍. ...

  6. 【并发】线程同步——锁Lock与synchronized比较

    一.简单使用Lock锁 Java 5中引入了新的锁机制--java.util.concurrent.locks中的显式的互斥锁:Lock接口,它提供了比synchronized更加广泛的锁定操作.Lo ...

  7. Linux下的C编程实战(开发平台搭建,文件系统编程,进程控制与进程通信编程,“线程”控制与“线程”通信编程,驱动程序设计,专家问答)

    Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来,Linux ...

  8. 【复习】进程、线程、协程篇,线程锁之Lock\Rlock\信号量、Event事件、Queue队列

    操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者消费者模型 ...

  9. linux多线程学习(五)——信号量线程控制

    在上一篇文章中,讲述了线程中互斥锁的使用,达到对共享资源互斥使用.除了使用互斥锁,信号量,也就是操作系统中所提到的PV原语,能达到互斥和同步的效果,这就是今天我们所要讲述的信号量线程控制. PV原语是 ...

最新文章

  1. linux shell unlink,linux shell中,unlink和rm命令有什么区别
  2. 例题6-2 铁轨(Rails, ACM/ICPC CERC 1997, UVa 514)
  3. Kubernetes StatefulSet源码分析
  4. Python常用库及模块
  5. Python学习笔记:装饰器
  6. CHM文件显示目录无法显示内容的解决方案
  7. 【教程】jQuery打造动态下滑菜单
  8. Build failed in step 'Installing CLooG for host'
  9. Java 创建、填充PDF表单域
  10. 国产操作系统要起来,这款Linux是你的菜吗?
  11. IT职业就业-学长有话说
  12. JAVA入门级教学之(三元运算符)
  13. Python学习笔记:演示多根继承
  14. Flutter教程(1)——快速预览
  15. 在C#中使用DevExpress中的ChartControl实现极坐标图
  16. MATLAB—隐函数绘图
  17. 安装esxi时候的No Network Adapters报错 解决办法
  18. 台电X80H平板安装ubantu
  19. 目标群体是什么意思_什么是目标客户群体?求解
  20. 零信任网络ZTNA及SDP概念理解

热门文章

  1. 最大公约数(GCD)算法与最小公倍数(LCM)算法-C++实现
  2. 怎么查电脑服务器的基本信息,怎么查电脑服务器的地址
  3. 陶泓达:周五黄金原油白银走势分析及操作建议
  4. 常见电路、元器件汇总
  5. css flex布局网页小游戏
  6. 2021-09-30-THZ-前置
  7. Arduino KY-024线性磁力霍尔传感器
  8. .Net Core 6.0 解决跨域
  9. 北达软微服务架构设计与实践圆满结束
  10. 针对 store_name 字段