java - 我根本没有得到线程同步

标签 java multithreading synchronization

所以我已经阅读了很多有关 Java 中的线程同步的内容。我目前正在尝试有界缓冲区问题。生产者将继续在缓冲区中生产产品,而消费者将继续消费它。

如果缓冲区已满,生产者将等待,然后再生产另一个产品。 如果缓冲区为空,消费者将等待。

但是,我的问题是生产者仅在缓冲区为空时才开始生产,直到缓冲区已满。消费者仅在缓冲区已满时才开始消费,直到缓冲区为空。

示例(缓冲区大小:5)

Produced Product 1
Produced Product 2
Produced Product 3
Produced Product 4
Produced Product 5
Consumed Product 1
Consumed Product 2
Consumed Product 3
Consumed Product 4
Consumed Product 5
Produced Product 6
Produced Product 7
Produced Product 8
Produced Product 9
Produced Product 10
Consumed Product 6
Consumed Product 7
Consumed Product 8
Consumed Product 9
Consumed Product 10
Produced Product 11
Produced Product 12
Produced Product 13
Produced Product 14
Produced Product 15
Consumed Product 11
Consumed Product 12
Consumed Product 13
Consumed Product 14
Consumed Product 15
Produced Product 16
Produced Product 17
Produced Product 18
Produced Product 19
Produced Product 20
Consumed Product 16
Consumed Product 17
Consumed Product 18
Consumed Product 19
Consumed Product 20
Produced Product 21
Produced Product 22
Produced Product 23
Produced Product 24
Produced Product 25
Consumed Product 21
Consumed Product 22
Consumed Product 23
Consumed Product 24
Consumed Product 25
Produced Product 26
Produced Product 27
Produced Product 28
Produced Product 29
Produced Product 30
Consumed Product 26
Consumed Product 27
Consumed Product 28
Consumed Product 29
Consumed Product 30

我希望只要缓冲区未满,生产者就生产,无论缓冲区是否为空。随后,我希望只要缓冲区不为空,无论缓冲区是否已满,消费者都可以消费。

我的代码有什么问题?

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import javax.swing.JOptionPane;

public class ProducerConsumer{

    final static Queue<Product> buffer = new LinkedList<>();
    private static int buffer_size, no_items, itemno = 1;
    private static Random r = new Random();
    public static void main(String[] args) {
        try{
            buffer_size = Integer.parseInt(JOptionPane.showInputDialog("Input Buffer size (default: 5)"));
            if(buffer_size<0){
                buffer_size = 5;
            }
        }catch(NumberFormatException nfe){
            buffer_size = 5;
        }
        try{
            no_items = Integer.parseInt(JOptionPane.showInputDialog("Input No. of Items (default: 10)"));
            if(no_items<0){
                no_items = 10;
            }
        }catch(NumberFormatException nfe){
            no_items = 10;
        }
        Producer producer = new Producer();
        Consumer consumer = new Consumer();
        producer.start();
        consumer.start();
    }

    static class Product {
        private String name = "Product X";
        private int productno;

        public Product(int productno) {
            this.productno = productno;
            this.name = "Product "+productno;
        }
        public int number() {
            return productno;
        }
        @Override
        public String toString() {
            return name;
        }
    }
    static class Producer extends Thread{
        public Producer(){
        }
        public void produce(){
            Product p = new Product(itemno++);
            try {
                this.sleep(r.nextInt(100));
            } catch (InterruptedException ex) {
                Thread.interrupted();
            }
            buffer.add(p);
            System.out.println("Produced "+p);
        }
        @Override
        public void run(){
            synchronized(buffer){
                while(itemno<=no_items){
                    while(buffer.size()==buffer_size){
                        try{
                            buffer.wait(100);
                        }catch(InterruptedException e){
                            Thread.interrupted();
                        }
                    }
                    produce();
                    buffer.notifyAll();
                }
            }
        }
    }
    static class Consumer extends Thread{
        public Consumer(){
        }
        public boolean consume(){
            try {
                this.sleep(r.nextInt(100));
            } catch (InterruptedException ex) {
                Thread.interrupted();
            }
            Product product = buffer.remove();
            System.out.println("Consumed "+product);
            return product.number()==no_items;
        }
        @Override
        public void run(){
            synchronized(buffer){
                boolean end = false;
                while(!end){
                    while(buffer.isEmpty()){
                        try{
                            buffer.wait(100);
                        }catch(InterruptedException e){
                            Thread.interrupted();
                        }
                    }
                    end = consume();
                    buffer.notifyAll();
                }
            }
        }
    }
}

最佳答案

这是因为您已经获取了 buffer 监视器并在 notifyAll 之前生成了 N 次,并通过退出 synchronized block 释放了缓冲区监视器,所有这些都在 while 循环内。

尝试将 while 放在 synchronized block 之外,这样您就可以让其他线程有机会在并发生产/消费期间获取锁。

请注意,在通知线程退出同步 区域之前,notifyAll 实际上不会影响其他线程

编辑:我在进行了建议的更改后运行了它,得到了以下输出

Produced Product 1
Produced Product 2
Produced Product 3
Consumed Product 1
Consumed Product 2
Consumed Product 3
Produced Product 4
Produced Product 5
Consumed Product 4
Consumed Product 5
Produced Product 6
Consumed Product 6
Produced Product 7
Produced Product 8
Produced Product 9
Produced Product 10
Consumed Product 7
Consumed Product 8
Consumed Product 9
Consumed Product 10

关于java - 我根本没有得到线程同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10237310/

相关文章:

java - Jackson MRBean 不工作,无法构造实例

java.lang.ClassCastException : java. lang.String 无法转换为 com.tutorial.stateful.Book

c# - 实时复制缓冲区数据

C#多线程-同步设置点

去 channel ,似乎没问题,但它陷入僵局

java - 从 java.sql.Timestamp 到 joda 的 LocalDate 的意外转换

multithreading - iOS 线程 "Modifying layer that is being finalized"

java - 您可以在多个线程上启动 Spring Boot Rest 应用程序吗?

c - C 中的同步对象及其与数据结构结构的关联

java - 如何持久化或保存 JavaFX UI 状态?