一般来说(单核),如果没有任务会阻塞,那么单处理器机器上使用并发就没有任何意义。
阻塞队列多半是解决对同一个(共享)资源进行操作的时候互相协作的问题。比如说有这样一个场景:某个工厂有生产工和搬运工两种角色,前者负责把生产好的产品放入仓库,
后者把仓库里面的产品搬出去卖。假如说仓库的产品数量为零,那么搬运工大可以睡上一觉,等生产工生产出产品,然后再搬。我们抽象出一个实现阻塞队列需要的元素,首先,仓库里面的产品是共享的资源,其次,生产工和搬运工需要互相协调这个资源的产生和消耗,他们应该是对应于程序中的两个线程,互不干扰又互相协调。
基于这个分析,我们就开始吧。
首先我们新建阻塞操作类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线程:大总结
【Java并发编程--BlockingQueue详解】 BlockingQueue 是 Java 并发包(java.util.concurrent)中的一个接口,它扩展了 Queue 接口,并...开发者可以根据实际需求选择不同类型的阻塞队列实现,以适应不同的并发场景。
队列在并发编程中扮演重要角色,例如作为生产者-消费者模型中的缓冲区,通过阻塞队列实现线程间的同步。 ### 三、Java 并发工具 Java并发包(`java.util.concurrent`)提供了许多工具类,如`ExecutorService`、`...
在Java编程中,多线程和队列是两个非常重要的概念,它们对于构建高效、可扩展的并发应用程序至关重要。队列工厂则是实现多线程间通信和任务调度的一种设计模式,它提供了一种抽象和统一的方式来创建和管理队列实例。...
通过以上分析可以看出,Java多线程加队列上传文件的实现不仅涉及基础的网络编程和文件操作知识,还需要掌握高级的多线程管理和并发控制技术。这种技术方案适用于需要高效处理大量文件上传请求的场景,比如云存储服务...
在Java编程中,"并发-线程池和阻塞队列"是两个核心概念,它们在多线程环境下处理任务调度和数据同步方面发挥着重要作用。线程池是一种管理线程资源的有效方式,而阻塞队列则常用于线程间通信和数据共享。 线程池...
总之,Java并发编程中的阻塞队列和阻塞栈是高效并发处理的核心工具,它们通过内置的阻塞机制实现线程间的同步,简化了多线程环境下的复杂性,提升了系统性能。了解并熟练掌握这些特性,对于任何Java开发者来说都是至...
在Java并发编程中,任务执行是核心概念之一,它涉及到如何高效地管理和调度多个任务,以充分利用多核处理器的计算能力并提高程序的响应速度。任务可以视为一个可执行的工作单元,通常通过实现`Runnable`接口或者使用...
综上所述,线程、线程池、集合和队列是Java并发编程的核心概念,理解和掌握它们对于开发高效、稳定的并发应用程序至关重要。在实际开发中,应根据具体需求选择合适的线程管理策略、数据结构和同步机制,以实现高性能...
Java中的ArrayBlockingQueue和LinkedBlockingQueue都是典型的阻塞队列实现。 阻塞队列为线程间通信提供了便捷的机制,可以用来协调多个线程的运行,防止多线程直接访问共享资源导致的并发问题。例如,生产者-消费者...
阻塞队列是一种在多线程编程中广泛使用的并发数据结构,它在计算机科学和编程领域,特别是Java和C++等面向对象语言中扮演着重要角色。标题中的“支持多线程和泛型的阻塞队列”意味着我们讨论的是一个能够同时处理多...
“消息队列Demo.zip”则可能包含了一个实现消息队列的示例,消息队列常用于处理并发操作,它允许组件之间异步通信,避免阻塞主线程,提高系统的响应性和可扩展性。在Android中,常见的消息队列实现是Handler-Message...
以上知识点覆盖了Java并发编程的主要方面,包括线程管理、同步机制、并发工具、设计模式、并发集合以及并发编程的最佳实践等,是理解和掌握Java并发编程的关键。在实际开发中,理解和熟练运用这些知识可以编写出高效...
Java的多线程是编程中的一个关键概念,特别是在并发处理和高性能应用中。本文将深入讲解如何在Java中实现多线程以及线程间的通信。 首先,我们要理解一个虚假的多线程示例。在例1中,创建了两个`TestThread`对象,...
Java的BlockingQueue阻塞队列可以实现线程间的生产者-消费者模式,通过put()和take()方法实现数据的传递。此外,Phaser、CyclicBarrier和CountDownLatch等同步辅助类也是线程间协调的重要工具。 线程池是Java并发...
线程池是Java并发编程中的重要概念,它有效地管理和控制线程的创建和销毁,提高了系统资源的利用率。Java中,可以通过`Executors`类创建不同类型的线程池: 1. **固定大小线程池**:`newFixedThreadPool(int ...
【Java线程聊天室(阻塞队列实现)】 在Java编程中,多线程是构建并发应用程序的关键技术。在创建一个线程聊天室时,我们通常会涉及到多个线程之间的交互,例如用户发送消息、接收消息以及处理网络通信等。而阻塞...
这个"高并发多线程处理demo-java.rar"压缩包提供了一个实际的Java实现,展示了如何构建一个并发队列来接收数据,并通过多线程进行处理。以下是对这个实例中的知识点进行的详细解释: 1. **Java多线程**:Java通过`...
Java线程池是一种高效管理并发任务的机制,它允许开发者预先配置一定数量的线程,以便在处理多个并发任务时能有效地复用这些线程,从而避免了频繁创建和销毁线程带来的开销。在Java中,`java.util.concurrent`包下的...
* 如何使用 Java 实现阻塞队列? 这个问题是检测候选者对 Java 多线程基础知识和实际编程能力的掌握情况。 3. 生产者——消费者问题 生产者——消费者问题是 Java 多线程并发编程中非常经典的问题。面试官通常会问...