使用synchronized 实现生产者和消费者,发现出现死锁,代码如下:
(wait notify nofityAll 方法,只能在监控器对象(锁对象)上调用)。
public class BlockingListBySync<E> implements BlockingList<E> { static final int MAXIMUM_CAPACITY = 1 << 30; int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; } Object items[]= null; volatile int count = 0; int putIndex =0; int takeIndex = 0; public BlockingListBySync(int size){ int realSize = tableSizeFor(size); items = new Object [realSize]; } /** * 生产对象 * @param e * @throws InterruptedException */ @Override public void put(E e) throws InterruptedException{ synchronized (this){ while(count ==items.length){ this.wait(); } putIndex ++; putIndex = putIndex & (items.length-1); items[putIndex]= e; count++; this.notify(); } } public int size(){ return count; } /** * 消费对象 * @return * @throws InterruptedException */ @Override public E take() throws InterruptedException{ synchronized (this){ while(count ==0){ this.wait(); } takeIndex ++; takeIndex = takeIndex & (items.length-1); count--; E e = (E)items[takeIndex]; items[takeIndex] = null; this.notify(); return e; } } }
多个生产线程调用put方法。
多个消费线程调用take方法。
运行结果:产生死锁。
原因分析:线程调用wait()方法之后,线程进入监控器对象的等待队列,那么在等待队列中即有生产者线程,也有消费都线程。当监控器对象的notify方被调用时,从等待队列中任意性选取一个线程唤醒,那么唤醒的线程 有可能是生产者线程,也有可能是消费者线程 。 如果生产线程唤醒的也是生产线程,那么很容易死锁。
简单来说:就是等待队列中有2种线程,生产线程想唤醒消费线程,但jvm是任意选取线程唤醒的,如果换醒了生产线程,可能进入死锁。
解决方法:
1.把nofity 换成notifyAll()
notifyAll()把监控器上等待队列中所有的线程唤醒,一定是包括了消费线程,所以可以。
2.可以使用ReentrantLock 创建两个Condition(空的和满的),可以区分线程类型
相关推荐
在Java编程中,生产者消费者模型是一种典型的多线程问题,用于解决资源的共享和并发控制。这个模型中,生产者负责生成数据,而...通过分析和运行这个项目,可以加深对生产者消费者模型和`synchronized`关键字的理解。
在Java编程中,死锁和生产者消费者问题是多线程编程中的两个重要概念,它们涉及到并发执行和资源管理。理解并正确处理这些问题对于构建高效、可靠的多线程应用至关重要。 死锁是指两个或多个线程在执行过程中,因...
生产者与消费者的模型是计算机科学中的一个经典多线程问题,主要探讨了如何在多线程环境下有效地管理和同步资源,以避免数据竞争和死锁。在这个实验中,我们将模拟一个场景,其中生产者线程负责生成产品并放入共享...
6. **死锁和饥饿**:在设计生产者-消费者模型时,需要注意避免死锁(两个或多个线程相互等待对方释放资源)和饥饿(某个线程因资源分配不当而永远无法执行)。例如,确保生产者不会无限等待消费者消费,消费者也不会...
生产者-消费者模型涉及到两个主要角色:生产者(Producer)和消费者(Consumer)。生产者负责生成数据或产品,并将其放入一个共享的缓冲区;而消费者则从这个缓冲区中取出并消费这些数据或产品。在我们的例子中,有...
`Buffer`类中的`put()`和`take()`方法使用`synchronized`关键字保证了线程安全,并使用`wait()`和`notifyAll()`来控制生产者和消费者的执行顺序。 在`Main`类中,我们创建了两个线程,一个作为生产者,另一个作为...
### Java生产者与消费者模型详解 #### 实验背景与目的 在并发编程中,生产者-消费者模式是一种经典的解决同步问题的设计模式。本实验旨在通过实际编程操作,深入理解Java中生产者与消费者模型的工作机制及其同步...
操作系统中的生产者-消费者问题是多线程编程中的经典案例,主要用来展示线程同步和通信的概念。在这个Java实现中,我们将深入理解这个问题的背景、原理以及如何通过Java的并发工具来解决。 生产者-消费者问题的基本...
使用synchronized关键字和wait()、notify()方法可以实现生产者消费者模式。生产者和消费者共享一个对象,这个对象包含一个计数器(表示缓冲区的大小)。生产者在生产完一个产品后调用notify()唤醒消费者,然后进入...
在Java中实现生产者与消费者模式时,通常会利用到同步机制如`synchronized`关键字以及`wait()`和`notifyAll()`等方法来确保线程之间的正确协作。 ## 代码分析 ### `Resource`类 `Resource`类是整个生产者与消费者...
在计算机科学中,生产者-消费者问题是多线程并发控制中的一个经典问题。它描述了两个不同的线程,生产者负责生成数据,而消费者则负责消耗这些数据。在这个Java实现中,我们将探讨如何使用Java的并发工具来解决这个...
在"生产者和消费者问题.txt"文件中,可能包含了使用`BlockingQueue`实现生产者消费者问题的Java代码示例,包括如何创建队列,以及生产者和消费者线程如何交互。而"哲学家就餐问题.txt"文件可能展示了如何用Java的...
Java生产者消费者模型是多线程编程中一种经典的并发控制模型,它源于操作系统中的哲学思想,用于解决资源的共享和异步处理问题。在该模型中,"生产者"线程负责生成数据,而"消费者"线程则负责消费这些数据。两者之间...
这样,生产者和消费者可以有效地协调它们的活动,避免数据竞争和死锁。 在示例代码中,有三个生产者线程和三个消费者线程,它们都是`Runnable`接口的实现,这意味着它们可以作为线程的目标对象。每个生产者线程会...
生产者与消费者模式是设计模式中的经典范例,它有效地展示了线程间的协作和同步。这个模式主要解决的问题是数据的生产和消费过程中的等待与协作问题。 在多线程环境下,生产者负责生成数据,而消费者则负责处理这些...
知识点:Java实现操作系统中的消费者生产者问题 ...在本例中,通过CircularBuffer类实现了生产者和消费者对共享缓冲区的同步访问,有效避免了数据竞争和死锁的情况,实现了数据的一致性和完整性。
- 在设计解决方案时,要避免死锁情况,即所有生产者都在等待消费者消费,而所有消费者都在等待生产者生产。合理的信号量管理可以防止这种情况发生。 5. **应用实例**: - 在实际操作系统中,生产者消费者模型常...
关键在于保证生产者不会在缓冲区满时生产,消费者不会在缓冲区空时消费,以免造成数据竞争和死锁。 **Java并发工具的使用:** 在Java中,我们可以使用`BlockingQueue`接口及其实现,如`ArrayBlockingQueue`,来简化...
除了`BlockingQueue`,Java还提供了其他同步工具,如`synchronized`关键字、`wait()`、`notify()`和`notifyAll()`方法,以及`ReentrantLock`、`Condition`等,它们都可以用来解决生产者消费者问题,但`BlockingQueue...
8. **死锁和饥饿**:在实现多线程生产者消费者模型时,必须警惕可能出现的死锁和饥饿问题。死锁是两个或更多线程相互等待对方释放资源导致的僵局,而饥饿则是指某一线程因为资源分配不公平而无法获得执行的机会。...