gpt4 book ai didi

java - 使用java同步理解生产者-消费者

转载 作者:行者123 更新时间:2023-12-02 03:00:36 28 4
gpt4 key购买 nike

我一直在研究 PC 问题,以了解 Java 同步和线程间通信。使用底部的代码,输出为

Producer produced-0
Producer produced-1
Producer produced-2
Consumer consumed-0
Consumer consumed-1
Consumer consumed-2
Producer produced-3
Producer produced-4
Producer produced-5
Consumer consumed-3
Consumer consumed-4

但是输出不应该像下面这样

Producer produced-0
Consumer consumed-0
Producer produced-1
Consumer consumed-1
Producer produced-2
Consumer consumed-2
Producer produced-3

我期望这样的输出,因为我的理解是,当方法终止时,生产方法释放锁后,消费者就会收到生成的值的通知。结果等待的消费者 block 进入同步状态获取锁来消费生产的值,同时生产者方法被阻塞。该锁在消费方法结束时释放,该锁由因同步而被阻塞的生产者线程获取,并且循环继续,因为每个方法因获取锁而被阻塞。

请告诉我我误解了什么?谢谢

package MultiThreading;

//Java program to implement solution of producer
//consumer problem.
import java.util.LinkedList;

public class PCExample2
{
public static void main(String[] args)
throws InterruptedException
{
// Object of a class that has both produce()
// and consume() methods
final PC pc = new PC();

// Create producer thread
Thread t1 = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
while (true) {
pc.produce();
}
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
});

// Create consumer thread
Thread t2 = new Thread(new Runnable()
{
@Override
public void run()
{
try
{
while (true) {
pc.consume();
}
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
});

// Start both threads
t1.start();
t2.start();

// t1 finishes before t2
t1.join();
t2.join();
}

// This class has a list, producer (adds items to list
// and consumber (removes items).
public static class PC
{
// Create a list shared by producer and consumer
// Size of list is 2.
LinkedList<Integer> list = new LinkedList<>();
int capacity = 12;
int value = 0;

// Function called by producer thread
public void produce() throws InterruptedException
{
synchronized (this)
{
// producer thread waits while list
// is full
while (list.size()==capacity)
wait();

System.out.println("Producer produced-"
+ value);

// to insert the jobs in the list
list.add(value++);

// notifies the consumer thread that
// now it can start consuming
notify();

// makes the working of program easier
// to understand
Thread.sleep(1000);
}
}

// Function called by consumer thread
public void consume() throws InterruptedException
{
synchronized (this)
{
// consumer thread waits while list
// is empty
while (list.size()==0)
wait();

//to retrive the ifrst job in the list
int val = list.removeFirst();


System.out.println("Consumer consumed-"
+ val);

// Wake up producer thread
notify();

// and sleep
Thread.sleep(1000);
}
}
}
}

最佳答案

如果其他线程也放弃了锁,那么第一个调用当前获取锁的线程(我们称之为线程 A)不一定会在锁的当前所有者线程放弃锁后立即获取锁。由于线程 A 试图获取锁,因此调用了该锁。没有有序的“队列”。请参阅herehere 。因此,从程序的输出来看,似乎在生产者释放锁之后,在生产者线程中的 while 循环执行之前,消费者可能没有足够的时间来获取锁。重复并且生产者线程再次调用锁(正如其他答案所指出的, Thread.sleep() 不会导致 sleep 线程放弃锁),并且如果消费者不幸,生产者将重新获取锁,即使消费者先在那里。

不过,似乎还有一个误会。生产者线程永远不会在 PC 上“等待”,直到列表包含 12 个元素,因此只有当生产者生成了至少 12 个元素(顺便说一下, ,就是我运行程序时发生的情况 - 消费者永远不会有机会,直到生产者线程在 PC 上调用 wait(),但随后,它会消耗整个列表)。这也意味着,如果恰好轮到消费者,并且列表包含的元素少于 12 个,则生产者线程将不会收到通知,因为它不是等待被通知,而只是被阻止并且已经,让我们说“预期”或“期待”PC 上的锁定(另请参阅 here 关于“等待”和“阻止”之间的区别)。因此,即使您将两个 Thread.sleep() 调用放在同步块(synchronized block)之外,从而为使用者线程(希望您不应该依赖于此)提供足够的时间来获取锁,调用消费者线程的 notify() 不会产生任何效果,因为生产者线程永远不会处于等待状态。

要真正确保两个线程交替修改 PC,您必须仅在列表大小大于零时才让生产者线程等待,而不是列表包含 12(或无论多少)元素。

关于java - 使用java同步理解生产者-消费者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45419884/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com