一般来说(单核),如果没有任务会阻塞,那么单处理器机器上使用并发就没有任何意义。
阻塞队列多半是解决对同一个(共享)资源进行操作的时候互相协作的问题。比如说有这样一个场景:某个工厂有生产工和搬运工两种角色,前者负责把生产好的产品放入仓库,
后者把仓库里面的产品搬出去卖。假如说仓库的产品数量为零,那么搬运工大可以睡上一觉,等生产工生产出产品,然后再搬。我们抽象出一个实现阻塞队列需要的元素,首先,仓库里面的产品是共享的资源,其次,生产工和搬运工需要互相协调这个资源的产生和消耗,他们应该是对应于程序中的两个线程,互不干扰又互相协调。
基于这个分析,我们就开始吧。
首先我们新建阻塞操作类BlockOperator,代码如下:
public class BlockOperator {
private Object notEmpty = new Object();
private Queue<Object> linkedList = new LinkedList<Object>();
/**
* 取物品
*
* @return
* @throws InterruptedException
*/
public Object take() throws InterruptedException {
synchronized (notEmpty) {
String cureadname = Thread.currentThread().getName();
System.out.println("搬运工" + cureadname + "来到仓库");
sleep(1000l);
if (linkedList.size() == 0) {
// 假如仓库没东西了,那么就先不取物品,此时释放锁,被唤醒之前,需要先得到锁
System.out.println("搬运工" + cureadname + "发觉没有物品,只能等待生产");
notEmpty.wait();
}
Object obj = linkedList.poll();//返回并删除此元素
System.out.println("搬运工" + cureadname + "这时看到有了物品,搬出了:" + obj
+ "仓库还有物品数量:" + linkedList.size());
return obj;
}
}
// 生产物品
public void offer(Object object) throws InterruptedException {
synchronized (notEmpty) {
String cureadname = Thread.currentThread().getName();
System.out.println("生产工" + cureadname + "来到仓库准备放物品");
sleep(3000l);
if (linkedList.size() == 0) {
// 假如仓库没东西了,唤醒对象锁。分析:这个时候有可能没有等待锁,也可能有。
System.out.println("生产工" + cureadname+ "发现来到仓库的时候一件物品都没有,发觉搬运工在睡觉等他或者感觉搬运工在等他,于是喊醒了它");
notEmpty.notifyAll();
/*
* 注 假如仓库有东西,那么不用唤醒搬运工,因为有物品的时候,搬运工不会等待。
* 分析:有的人肯定会觉得,有没有这种可能:当linkedList.size=0的时候,notEmpty就wait了,然后在本同步块中,
* 发现linkedList.size!=0,那么notEmpty就不会去唤醒了。其实这完全没有可能,因为size!=0只有在完成了
* linkedList.add之后才有可能,而在add之前,必然会判断size=0的情况
*/
}
System.out.println("生产工" + cureadname + "把物品" + object
+ "放到了仓库");
linkedList.add(object);
}
}
private void sleep(Long time) {
try {
Thread.sleep(time);// 模拟时间消耗
} catch (InterruptedException e) {
e.printStackTrace();
}
}
注:本类中,首先创建了一个notEmpty做锁的对象,取物品的时候当产品为0时,notEmpty等待,此时会让位与另一个线程(生产)得到此对象锁,并且唤醒notEmpty上所有的等待锁。在生产完成之后,由于刚才等待的线程已经被唤醒,那么这个搬运工会移除此产品。下面会有我本机运行的效果,对照看一下会一目了然
然后创建生产工线程类CreateProduce,代码如下:
/**
* 模拟工厂生产产品
*
* @author Administrator
*
*/
public class CreateProduce implements Runnable {
private BlockOperator bq;
public CreateProduce(BlockOperator bq){
this.bq=bq;
}
@Override
public void run() {
//生产n个产品
for(int i=0;i<5;i++){
Object obj="A"+i;
try {
bq.offer(obj);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
此类比较简单,创建5个商品。
继续创建搬运工线程类,代码如下
/**
* 模拟工厂搬运产品
* @author Administrator
*
*/
public class GetProduce implements Runnable {
private BlockOperator bq;
public GetProduce(BlockOperator bq){
this.bq=bq;
}
@Override
public void run() {
try {
//搬运工是有多少搬多少
while(true){
Object obj=bq.take();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
最后新建一个测试类 如下:
public class TestMain {
public static void main(String[] args) {
BlockOperator bq = new BlockOperator();
Thread createThread = new Thread(new CreateProduce(bq),"creater");
Thread getThread = new Thread(new GetProduce(bq),"getter");
createThread.start();
getThread.start();
}
}
在我本地运行的结果如下:
当我准备想在BlockOperator里面加一个判断产品最大数量的锁对象,比如TheMaxObject,后来在take和offer里面分别加上限制,但是免不了会嵌套synchronized,那么这样会产生死锁。死锁大多是嵌套synchronized产生的。
- 大小: 97.9 KB
分享到:
相关推荐
详细的讲述了多线程的各种用法 Java线程:概念与原理 ...Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-条件变量 Java线程:新特征-原子量 Java线程:新特征-障碍器 Java线程:大总结
Java 线程系列博文总结word化,编目如下,欢迎互相学习交流: ...Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-条件变量 Java线程:新特征-原子量 Java线程:新特征-障碍器
Java线程:概念与原理 Java线程:创建与启动 ...Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-条件变量 Java线程:新特征-原子量 Java线程:新特征-障碍器 Java线程:大总结
资源概要:1,多线程;2,synchronized;3,volatile;4,多线程在JVM中的实现原理剖析 导语: 什么是多线程? 多线程(multithreading...并发工具类、并发容器、阻塞队列 线程池原理剖析 线程池案例-Web容器-压力测试
使用非阻塞队列的时候有一个很大问题是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,必须额外地实现同步策略以及线程间唤醒策略,这个实现起来非常麻烦。但是有了阻塞队列不一样了,它会
5.3 阻塞队列和生产者-消费者模式 5.3.1 示例:桌面搜索 5.3.2 串行线程封闭 5.3.3 双端队列与工作密取 5.4 阻塞方法与中断方法 5.5 同步工具类 5.5.1 闭锁 5.5.2 FutureTask 5.5.3 信号量 5.5.4 栅栏 5.6...
java并发库thread使用,传统线程技术、定时器技术、线程互斥技术,同步通讯技术、多线程共享数据、并发库应用,线程锁技术,阻塞锁、阻塞队列,线程池等应用
详细介绍java并发编程相关知识: ... 阻塞队列 高级线程协作工具 信号量 闭锁 关卡 fork-join Executor部分 Executor基础 ThreadPoolExecutor的定制 线程的中断与任务的取消 其他
Java并发编程常见知识点源码集锦,涉及到对象锁,Executors多任务线程框架,线程池等示例,列出一些源码包中包括的内容: volatile关键字的非原子性、volatile关键字的使用、AtomicInteger原子性操作、线程安全小...
5.3 阻塞队列和生产者-消费者模式 5.3.1 示例:桌面搜索 5.3.2 串行线程封闭 5.3.3 双端队列与工作密取 5.4 阻塞方法与中断方法 5.5 同步工具类 5.5.1 闭锁 5.5.2 FutureTask 5.5.3 信号量 5.5.4 栅栏 5.6...
Java中的阻塞队列原理与使用.mp4 实战:简单实现消息队列.mp4 并发容器ConcurrentHashMap原理与使用.mp4 线程池的原理与使用.mp4 Executor框架详解.mp4 实战:简易web服务器(一).mp4 实战:简易web服务器(二)....
本书的读者是那些具有一定Java编程经验的程序员、希望了解Java SE 5,6在线程技术上的改进和新特性的程序员,以及Java和并发编程的爱好者。 目录 代码清单 序 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的...
第49节Java中的阻塞队列原理与使用00:26:18分钟 | 第50节实战:简单实现消息队列00:11:07分钟 | 第51节并发容器ConcurrentHashMap原理与使用00:38:22分钟 | 第52节线程池的原理与使用00:42:49分钟 | 第53节...
《java并发编程实战》读书笔记-第3章-对象的共享,脑图形式,使用xmind8制作 包括同步容器类、并发容器类、阻塞队列和生产者消费者模式、阻塞和中断方法、同步工具类。最后是构建高效且可伸缩的结果缓存
5.3 阻塞队列和生产者一消费者模式 5.4 阻塞和可中断的方法 5.5 synchronizer 5.6 为计算结果建立高效、可伸缩的高速缓存 第2部分 构建并发应用程序 第6章 任务执行 6.1 在线程中执行任务 6.2 executor 框架 6.3 ...
---【课时12】12-进程内线程通讯实现(手写阻塞式队列).mp4 ---【课时2】02-如何理解线程安全与不安全.mp4 ---【课时3】03-导致线程不安全的因素.mp4 ---【课时4】04-如何保证线程安全.mp4 ---【课时5】05-...
Java并发编程 背景介绍 并发历史 必要性 进程 资源分配的最小单位 线程 CPU调度的最小单位 线程的优势 (1)如果设计正确,多线程程序可以通过提高处理器资源的利用率来提升系统吞吐率 ...
如果你是一名Java开发人员,并且想进一步掌握并发编程和多线程技术,并挖掘Java 7并发的新特性,那么本书是你的合适之选。 《Java 7并发编程实战手册》 第1章 线程管理 1 1.1 简介 1 1.2 线程的创建和运行...