博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
细粒度的线程控制?使用Lock Condition~
阅读量:7100 次
发布时间:2019-06-28

本文共 7896 字,大约阅读时间需要 26 分钟。

  hot3.png

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

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

/** * Created by Anur IjuoKaruKas on 6/28/2018 */@SuppressWarnings("Duplicates")public class Restaurant {    private final Lock kitchen = new ReentrantLock();    private ConcurrentLinkedDeque
meetFridge = new ConcurrentLinkedDeque<>();// 肉冰箱 public Runnable cockMeet() { return new Runnable() { @Override public 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() { @Override public 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
meetFridge = new ConcurrentLinkedDeque<>();// 肉冰箱 private ConcurrentLinkedDeque
vegeFridge = new ConcurrentLinkedDeque<>();// 菜冰箱 public Runnable cockMeet() { return new Runnable() { @Override public 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() { @Override public 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() { @Override public 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
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() { @Override public void run() { task.sout(finalI + ""); } }); executorService.execute(new Runnable() { @Override public void run() { task.mission(); } }); } }}

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

你可能感兴趣的文章
spring cloud互联网分布式微服务云平台规划分析--spring cloud服务统一配置中心
查看>>
【Flask】关于request.json /.values /.args /.form
查看>>
Virtualbox虚拟Ubuntu共享文件夹设置
查看>>
ubuntu上安装lua
查看>>
完全检查点与增量检查点的区别
查看>>
rhel5.4安装oracle10g图文步骤1
查看>>
未能加载文件或程序集“AspNetPager”或它的某一个依赖项。参数错误。
查看>>
Java之JVM内存结构、Java内存模型、Java对象模型
查看>>
distribute-list分发列表详解
查看>>
关于Oracle归档进程的运行机制
查看>>
mail退信分析大全
查看>>
grep命令以及正则表达式,算数运算.
查看>>
php生成随机密码的几种方法
查看>>
我的友情链接
查看>>
在防火墙配置自定义服务
查看>>
vSphere 6.0 -Difference between vSphere 5.0, 5.1, 5.5 and vSphere 6.0
查看>>
Collect VMware support log&Performance Snapshot
查看>>
Enable PowerShell script execution policy
查看>>
aix 设置主机信任
查看>>
编程题:输入一串字符,程序会自动将大写字母转换为小写
查看>>