`
AngelAndAngel
  • 浏览: 230613 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java并发线程-----阻塞队列的实现和思考

阅读更多
     一般来说(单核),如果没有任务会阻塞,那么单处理器机器上使用并发就没有任何意义。   
     阻塞队列多半是解决对同一个(共享)资源进行操作的时候互相协作的问题。比如说有这样一个场景:某个工厂有生产工和搬运工两种角色,前者负责把生产好的产品放入仓库,
后者把仓库里面的产品搬出去卖。假如说仓库的产品数量为零,那么搬运工大可以睡上一觉,等生产工生产出产品,然后再搬。我们抽象出一个实现阻塞队列需要的元素,首先,仓库里面的产品是共享的资源,其次,生产工和搬运工需要互相协调这个资源的产生和消耗,他们应该是对应于程序中的两个线程,互不干扰又互相协调。
     基于这个分析,我们就开始吧。
     首先我们新建阻塞操作类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
分享到:
评论
3 楼 wmj007 2011-09-13  
学习思路自己扩展
2 楼 liaohexiang 2011-08-27  
锁的粒度太大了,producer 和 consumer 在同一时间只能有一个进入queue中,可以看看concurrent包里的BlockingQueue
1 楼 panjun 2011-08-25  

相关推荐

    java多线程编程总结

    详细的讲述了多线程的各种用法 Java线程:概念与原理 ...Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-条件变量 Java线程:新特征-原子量 Java线程:新特征-障碍器 Java线程:大总结

    Java多线程编程总结

    Java 线程系列博文总结word化,编目如下,欢迎互相学习交流: ...Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-条件变量 Java线程:新特征-原子量 Java线程:新特征-障碍器

    Java 线程总结

    Java线程:概念与原理 Java线程:创建与启动 ...Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-条件变量 Java线程:新特征-原子量 Java线程:新特征-障碍器 Java线程:大总结

    Java-并发(Concurrent)编程

    资源概要:1,多线程;2,synchronized;3,volatile;4,多线程在JVM中的实现原理剖析 导语: 什么是多线程? 多线程(multithreading...并发工具类、并发容器、阻塞队列 线程池原理剖析 线程池案例-Web容器-压力测试

    Java并发编程:阻塞队列

     使用非阻塞队列的时候有一个很大问题是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,必须额外地实现同步策略以及线程间唤醒策略,这个实现起来非常麻烦。但是有了阻塞队列不一样了,它会

    Java并发编程实战

    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并发库高级应用源码--张孝祥

    java并发库thread使用,传统线程技术、定时器技术、线程互斥技术,同步通讯技术、多线程共享数据、并发库应用,线程锁技术,阻塞锁、阻塞队列,线程池等应用

    并发编程实践,全面介绍基础知识、JVM同步原语、线程安全、低级并发工具、线程安全容器、高级线程协作工具、Executor部分等

    详细介绍java并发编程相关知识: ...  阻塞队列 高级线程协作工具   信号量   闭锁   关卡 fork-join Executor部分   Executor基础 ThreadPoolExecutor的定制   线程的中断与任务的取消   其他

    Java并发编程相关源码集 包括多任务线程,线程池等.rar

    Java并发编程常见知识点源码集锦,涉及到对象锁,Executors多任务线程框架,线程池等示例,列出一些源码包中包括的内容:  volatile关键字的非原子性、volatile关键字的使用、AtomicInteger原子性操作、线程安全小...

    Java 并发编程实战

    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并发编程原理与实战

    Java中的阻塞队列原理与使用.mp4 实战:简单实现消息队列.mp4 并发容器ConcurrentHashMap原理与使用.mp4 线程池的原理与使用.mp4 Executor框架详解.mp4 实战:简易web服务器(一).mp4 实战:简易web服务器(二)....

    Java并发编程实践 PDF 高清版

    本书的读者是那些具有一定Java编程经验的程序员、希望了解Java SE 5,6在线程技术上的改进和新特性的程序员,以及Java和并发编程的爱好者。 目录 代码清单 序 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的...

    龙果java并发编程完整视频

    第49节Java中的阻塞队列原理与使用00:26:18分钟 | 第50节实战:简单实现消息队列00:11:07分钟 | 第51节并发容器ConcurrentHashMap原理与使用00:38:22分钟 | 第52节线程池的原理与使用00:42:49分钟 | 第53节...

    《java并发编程实战》读书笔记-第5章-基础构建模块

    《java并发编程实战》读书笔记-第3章-对象的共享,脑图形式,使用xmind8制作 包括同步容器类、并发容器类、阻塞队列和生产者消费者模式、阻塞和中断方法、同步工具类。最后是构建高效且可伸缩的结果缓存

    JAVA并发编程实践_中文版(1-16章全)_1/4

    5.3 阻塞队列和生产者一消费者模式 5.4 阻塞和可中断的方法 5.5 synchronizer 5.6 为计算结果建立高效、可伸缩的高速缓存 第2部分 构建并发应用程序 第6章 任务执行 6.1 在线程中执行任务 6.2 executor 框架 6.3 ...

    在线 Java 硕士加薪课程 Term-05 班 (10.68G)

    ---【课时12】12-进程内线程通讯实现(手写阻塞式队列).mp4 ---【课时2】02-如何理解线程安全与不安全.mp4 ---【课时3】03-导致线程不安全的因素.mp4 ---【课时4】04-如何保证线程安全.mp4 ---【课时5】05-...

    Java并发编程(学习笔记).xmind

    Java并发编程 背景介绍 并发历史 必要性 进程 资源分配的最小单位 线程 CPU调度的最小单位 线程的优势 (1)如果设计正确,多线程程序可以通过提高处理器资源的利用率来提升系统吞吐率 ...

    Java 7并发编程实战手册

    如果你是一名Java开发人员,并且想进一步掌握并发编程和多线程技术,并挖掘Java 7并发的新特性,那么本书是你的合适之选。 《Java 7并发编程实战手册》 第1章 线程管理 1 1.1 简介 1 1.2 线程的创建和运行...

Global site tag (gtag.js) - Google Analytics