Java 我不知道';根本无法获得线程同步

Java 我不知道';根本无法获得线程同步,java,multithreading,synchronization,Java,Multithreading,Synchronization,所以我读了很多关于Java中线程同步的书。我目前正在尝试有界缓冲区问题。当消费者继续消费产品时,生产者将继续在缓冲区中生产产品 如果缓冲区已满,生产商将等待,然后再生产另一种产品。 如果缓冲区为空,使用者将等待 然而,我的问题是,生产者只有在缓冲区为空时才开始生产,直到缓冲区满为止。消费者仅在缓冲区已满时开始消费,直到缓冲区为空为止 示例(缓冲区大小:5) 我希望这样,只要缓冲区未满,无论缓冲区是否为空,生产者都会生产。随后,我希望这样,只要缓冲区不是空的,无论缓冲区是否已满,消费者都会消费 我

所以我读了很多关于Java中线程同步的书。我目前正在尝试有界缓冲区问题。当消费者继续消费产品时,生产者将继续在缓冲区中生产产品

如果缓冲区已满,生产商将等待,然后再生产另一种产品。 如果缓冲区为空,使用者将等待

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

示例(缓冲区大小:5)

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

我的代码怎么了

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();
                }
            }
        }
    }
}
import java.util.LinkedList;
导入java.util.Queue;
导入java.util.Random;
导入javax.swing.JOptionPane;
公共类生产者消费者{
最终静态队列缓冲区=新LinkedList();
私有静态int缓冲区大小,无项,项号=1;
私有静态随机r=新随机();
公共静态void main(字符串[]args){
试一试{
buffer_size=Integer.parseInt(JOptionPane.showInputDialog(“输入缓冲区大小(默认值:5)”);

如果(buffer_size这是因为在退出
synchronized
块之前,您已经获取了
buffer
监视器并生成了N次,所有这些都在while循环内

尝试将
while
放在
synchronized
块之外,这样就可以让另一个线程在并发生产/消费期间获得锁

请注意,
notifyAll
实际上不会影响其他线程,直到通知线程退出
synchronized
区域

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

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

这是因为在退出
synchronized
块之前,您已经获取了
缓冲区
监视器并生成了N次,所有这些都在while循环中

尝试将
while
放在
synchronized
块之外,这样就可以让另一个线程在并发生产/消费期间获得锁

请注意,
notifyAll
实际上不会影响其他线程,直到通知线程退出
synchronized
区域

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

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

由于两个线程在缓冲区上都是同步的,因此在任何时候都只有一个线程在运行。一个线程向另一个线程发出恢复运行的信号,并在调用buffer.wait()时挂起自身。包含buffer.wait()的while循环中的逻辑调用,(buffer.size()==buffer\u size)和(buffer.isEmpty()),只允许循环在其功能(生产者或消费者)已完成且无法继续时运行

程序的执行方式如下:Producer将生成5项,然后while循环条件将为true,它将调用buffer.wait()以允许consumer运行。consumer将开始运行并使用,直到buffer为空,在这种情况下while条件将为true,它将调用buffer.wait()并允许Producer再次运行

要允许两个线程同时运行(这可能是您真正想要的),您应该仅在需要安全访问缓冲区时调用synchronize(buffer)。一种方法是使用以下代码块:

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();
        }
        synchronized(buffer) {
            buffer.add(p);
        }
        System.out.println("Produced " + p);
    }

    @Override
    public void run() {
        while (itemno <= no_items) {
            while (buffer.size() == buffer_size) {
                try {
                    sleep(100);
                } catch (InterruptedException e) {
                    Thread.interrupted();
                }
            }

            produce();
        }
    }
}

static class Consumer extends Thread {
    public Consumer() {
    }

    public boolean consume() {
        try {
            this.sleep(r.nextInt(100));
        } catch (InterruptedException ex) {
            Thread.interrupted();
        }

        Product product;
        synchronized (buffer) {
            product = buffer.remove();
        }

        System.out.println("Consumed " + product);
        return product.number() == no_items;
    }

    @Override
    public void run() {
        boolean end = false;
        while (!end) {
            while (buffer.isEmpty()) {
                try {
                    sleep(100);
                } catch (InterruptedException ex) {
                    Logger.getLogger(TrashMe.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            end = consume();
        }
    }
}
静态类生成器扩展线程{
公共制片人(){
}
公共产品{
产品p=新产品(itemno++);
试一试{
睡眠(r.nextInt(100));
}捕获(中断异常例外){
Thread.interrupted();
}
已同步(缓冲区){
添加(p);
}
系统输出打印项次(“生产”+p);
}
@凌驾
公开募捐{

while(itemno由于两个线程都在缓冲区上同步,因此在任何时候都只有一个线程在运行。一个线程向另一个线程发出信号,要求其恢复运行,并在调用buffer.wait()时挂起自身。包含buffer.wait()的while循环中的逻辑调用,(buffer.size()=buffer\u size)和(buffer.isEmpty()),只允许循环在其功能(生产者或消费者)已完成且无法继续时运行

程序的执行方式如下:Producer将生成5项,然后while循环条件将为true,它将调用buffer.wait()以允许consumer运行。consumer将开始运行并使用,直到buffer为空,在这种情况下while条件将为true,它将调用buffer.wait()并允许Producer再次运行

要允许两个线程同时运行(这可能是您真正想要的),您应该仅在需要安全访问缓冲区时调用synchronize(buffer)。一种方法是使用以下代码块:

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();
        }
        synchronized(buffer) {
            buffer.add(p);
        }
        System.out.println("Produced " + p);
    }

    @Override
    public void run() {
        while (itemno <= no_items) {
            while (buffer.size() == buffer_size) {
                try {
                    sleep(100);
                } catch (InterruptedException e) {
                    Thread.interrupted();
                }
            }

            produce();
        }
    }
}

static class Consumer extends Thread {
    public Consumer() {
    }

    public boolean consume() {
        try {
            this.sleep(r.nextInt(100));
        } catch (InterruptedException ex) {
            Thread.interrupted();
        }

        Product product;
        synchronized (buffer) {
            product = buffer.remove();
        }

        System.out.println("Consumed " + product);
        return product.number() == no_items;
    }

    @Override
    public void run() {
        boolean end = false;
        while (!end) {
            while (buffer.isEmpty()) {
                try {
                    sleep(100);
                } catch (InterruptedException ex) {
                    Logger.getLogger(TrashMe.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            end = consume();
        }
    }
}
静态类生成器扩展线程{
公共制片人(){
}
公共产品{
产品p=新产品(itemno++);
试一试{
睡眠(r.nextInt(100));
}捕获(中断异常例外){
Thread.interrupted();
}
已同步(缓冲区){
添加(p);
}
系统输出打印项次(“生产”+p);
}
@凌驾
公开募捐{

while(itemno)也是一个旁注。你应该使用
Thread.sleep(millis)
而不是
这个。sleep(millis)
sleep
是一个静态方法,总是在
Thread.currentThread()上执行
这反过来会对你有用,因为你正以这种方式使用它,但它可能会在将来烧死你。另外,顺便说一句,你应该