生产者-消费者应用程序上的Java多线程查询

生产者-消费者应用程序上的Java多线程查询,java,multithreading,producer-consumer,Java,Multithreading,Producer Consumer,我已经编写了一个简单的java多线程程序 我有一些关于代码的问题。请帮我回答这些问题 提前谢谢 这是我的密码: Producer.java package com.prodcon; import java.util.Stack; public class Producer extends Thread { DataStorage data; MainProcess tempmp; public Producer(DataStorage dst, MainProcess m

我已经编写了一个简单的java多线程程序

我有一些关于代码的问题。请帮我回答这些问题

提前谢谢

这是我的密码:

Producer.java

package com.prodcon;
import java.util.Stack;
public class Producer extends Thread {
    DataStorage data;
    MainProcess tempmp;
    public Producer(DataStorage dst, MainProcess mp){
        data = dst;
        tempmp = mp;
    }
    public void run(){
        for(int i = 0; i < 3; i++){
            System.out.println("Thread:"+this.getName()+"called");
            data.PutData();
            /*-------------current states---------------------*/
            System.out.println("Current states of the threads:");
            System.out.println("p1->"+tempmp.p1.getState());
            System.out.println("p2->"+tempmp.p2.getState());
            System.out.println("p3->"+tempmp.p3.getState());
            System.out.println("c1->"+tempmp.c1.getState());
            System.out.println("c2->"+tempmp.c2.getState());
            System.out.println("c3->"+tempmp.c3.getState());
            /*-------------current states---------------------*/

        }
    }
}
这是这个程序的输出:

    Thread:p2called
Thread:p3called
Current states of the threads:
Thread:p1called
Current states of the threads:
Thread:c3called
Current states of the threads:
p1->RUNNABLE
p2->BLOCKED
p3->RUNNABLE
c1->BLOCKED
c2->BLOCKED
c3->BLOCKED
Thread:p3called
Current states of the threads:
p1->RUNNABLE
p2->BLOCKED
p3->RUNNABLE
c1->BLOCKED
c2->BLOCKED
c3->BLOCKED
Thread:p3called
Thread:c2called
Thread:c1called
Current states of the threads:
Current states of the threads:
p1->RUNNABLE
Current states of the threads:
p2->BLOCKED
p1->RUNNABLE
p2->BLOCKED
p3->BLOCKED
c1->BLOCKED
c2->BLOCKED
c3->BLOCKED
Thread:p1called
Current states of the threads:
p1->RUNNABLE
p2->BLOCKED
p3->BLOCKED
c1->BLOCKED
c2->BLOCKED
c3->BLOCKED
Thread:p1called
Current states of the threads:
p1->RUNNABLE
p2->BLOCKED
p3->BLOCKED
c1->RUNNABLE
c2->RUNNABLE
c3->BLOCKED
Thread:c1called
Current states of the threads:
p1->BLOCKED
p2->BLOCKED
p3->BLOCKED
c1->RUNNABLE
c2->RUNNABLE
c3->BLOCKED
Thread:c1called
Current states of the threads:
p1->BLOCKED
p2->BLOCKED
p3->BLOCKED
c1->RUNNABLE
c2->RUNNABLE
c3->BLOCKED
Current states of the threads:
p1->RUNNABLE
p2->BLOCKED
p3->BLOCKED
c1->TERMINATED
c2->RUNNABLE
c3->BLOCKED
p1->RUNNABLE
p2->BLOCKED
p3->BLOCKED
c1->TERMINATED
c2->BLOCKED
c3->RUNNABLE
Thread:c3called
Current states of the threads:
p1->TERMINATED
p2->BLOCKED
p3->BLOCKED
c1->TERMINATED
c2->BLOCKED
c3->RUNNABLE
Thread:c3called
Current states of the threads:
p1->TERMINATED
p2->BLOCKED
p3->BLOCKED
c1->TERMINATED
c2->BLOCKED
c3->RUNNABLE
p3->RUNNABLE
p1->BLOCKED
p2->RUNNABLE
p3->RUNNABLE
c1->TERMINATED
c2->BLOCKED
c3->TERMINATED
Thread:p2called
Current states of the threads:
p1->TERMINATED
p2->RUNNABLE
p3->RUNNABLE
c1->TERMINATED
c2->BLOCKED
c3->TERMINATED
Thread:p2called
Current states of the threads:
p1->TERMINATED
p2->RUNNABLE
p3->RUNNABLE
c1->TERMINATED
c2->BLOCKED
c3->TERMINATED
p1->TERMINATED
p2->TERMINATED
p3->RUNNABLE
c1->TERMINATED
c2->RUNNABLE
c3->TERMINATED
Thread:c2called
Current states of the threads:
p1->TERMINATED
p2->TERMINATED
p3->RUNNABLE
c1->TERMINATED
c2->RUNNABLE
c3->TERMINATED
Thread:c2called
Current states of the threads:
p1->TERMINATED
p2->TERMINATED
p3->RUNNABLE
c1->TERMINATED
c2->RUNNABLE
c3->TERMINATED
c1->TERMINATED
c2->TERMINATED
c3->TERMINATED
我的问题是:

1.根据程序,这个过程永远不会停止…但是有些线程会自动终止,为什么

2.即使在请求某些线程进入等待状态后..根据输出,没有线程进入等待状态。为什么和如何

3.根据本准则:生产者和消费者问题之间的区别是什么 读者-作者问题


再次感谢

第一和第二个问题-由于逻辑原因,此代码自然存在。尝试在此处添加调试输出,以查看生产者何时退出

if (data.size() == 3) {
    try {
        wait();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
} else {
    System.out.printf("%s: breaking as data size is %d, %d%n", Thread.currentThread().getName(), countofdata, data.size());

    break;
}
另一个可能的问题是:

for(int i = 0; i < 3; i++){
    data.PutData();
}

我可以看出您非常热衷于使用线程,这是问题的主题,但您是否考虑过观察者/可观察者

数据存储是您可以观察到的

消费者是观察者。他们在寻求改变

我修改了您的代码,只有一个线程定期运行

制作人:

 public class Producer{
    DataStorage data;
    MainProcess tempmp;

    public Producer(DataStorage dst, MainProcess mp){
        data = dst;
        tempmp = mp;
    }
    public void changeTheData(){

            data.PutData();
            System.out.println("INFO :: Producer :: Just put data");
    }
}
消费者:

 import java.util.Observable;
 import java.util.Observer;
 import java.util.Stack;
 import java.util.concurrent.atomic.AtomicReference;

 public class Consumer implements Observer {
    DataStorage data;
    MainProcess tempmp;
    public Consumer(DataStorage dst, MainProcess mp){
        data = dst;
        tempmp = mp;
    }


 public void update(Observable arg0, Object arg1) {
    System.out.println("INFO :: class is " + arg1.getClass().toString());
    System.out.println("INFO :: Consumer :: data is " + ((AtomicReference<Double>)arg1).get());


}
}

只是一个提示尝试调试大量的sysout行,您会发现控件何时何地离开线程。但即使这些sysout行也没有正确打印。您可以从代码和实际输出中看到。输出和sysout行的顺序非常不同。生产者消费者与读写器消费者是一样的。区别可能在于生产者-消费者意味着项目的FIFO(生产者等待,直到所产生的项目被消费),而读写器则专注于锁定共享资源的随机访问区域。这意味着任意数量的读卡器或无读卡器可以逐个或同时读取一个资源。然而,这在producer consumer中是不可能的,这意味着
read=resource consumered
,因此,只读取一次。我仍然对前两个问题的答案感到困惑。当producer发现数据存储已满时,它应该等待,但在这里它将被终止!为什么?感谢第三个问题的答案,我得到了这个概念:)…但是如果我在程序中使用“synchronized”关键字,那么我如何允许一次进行多个读取?“synchronized”因为该方法意味着对
对象的独占访问。这是一种非常原始的同步方法,当你的队列所在的应用程序中CPU密集的部分有很多同步方法时,这是一种不好的味道。因此,您将无法从不同线程对单个数据源进行多次读取。要做到这一点,你可以。。。我会更新答案。好的,谢谢你的回答…如果我在每次GetData()调用中都要求读锁,那么也只有一个读卡器可以读取数据,即获得读锁的读卡器,写吗?多个读卡器如何读取数据?PutData()部分按照算法工作:)再次感谢!我认为,在GetData方法中,我们不应该获取readLock,而应该获取writeLock,这样所有写入程序都会被阻止,但读卡器不会被阻止!。。我不知道这是对还是错?这只是我的观点。如果我发布了任何错误的想法,请道歉!:p“GetData()调用,则只有一个读卡器可以读取数据,即获取读锁的读卡器”-是
ReadWriteLock
没有此问题。”我认为,在GetData方法中,我们不应该获取readLock,而应该获取writeLock,这样所有写入程序都会被阻止,但读卡器不会被阻止!'-它有同样的问题,就像你最初的解决方案
ReadWriteLock
是一项非常重要的任务,您可能需要研究
ReentrantReadWriteLock
实现。感谢tony提供新代码!我相信它会对我非常有用。顺便告诉我一件事,你的程序何时终止,如何终止?:)我在Eclipse中构建并运行了它。当它运行时,我想停止它,我只需单击控制台中的红色按钮,就可以停止它!我也在使用eclipse,但我的问题是……我上面提到的程序会自动终止,但您的程序会继续运行吗?不是吗?如何运行呢?我的持续运行的原因是我使用了ScheduledExecutorService,它计划在5秒后启动,然后每10秒以固定速率运行。它正在进行中。因为mainProcess是可运行的,所以它有一个run方法。ScheduledExtructorService.scheduleAtFixedRate作为参数:1。可运行类,2。延迟启动3。多长时间跑一次和4次。时间单位。并发库非常有用。我希望Obsrever/Observable能帮到你。
for(int i = 0; i < 3; i++){
    data.PutData();
}
final Object readLock = new Object(); //use objects as locks final Object writeLock = new Object();
public void GetData() {
    synchronized (readLock) {             // acquire only the read lock
        while (data.isEmpty()) {
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
            }

        }
        double temp = (double) data.pop();
        //System.out.println("Data poped out:" + temp);
        countofdata++;
        System.out.printf("%s: %d, %d%n", Thread.currentThread().getName(), countofdata, data.size());
        notifyAll();        
     }
 }

public void PutData() {
    synchronized (readLock) {       //first, acquire the read lock
        synchronized (writeLock) {  // then acquire the write lock
            while (true) {
                if (data.size() == 3) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                } else {
                    System.out.printf("%s: breaking as data size is %d, %d%n", Thread.currentThread().getName(), countofdata, data.size());

                    break;
                }
            }
            double temp = Math.random();
            data.push(temp);
            //System.out.println("Data inserted in storage:" + temp);
            countofdata--;
            notifyAll();
        }
    }
}
 public class Producer{
    DataStorage data;
    MainProcess tempmp;

    public Producer(DataStorage dst, MainProcess mp){
        data = dst;
        tempmp = mp;
    }
    public void changeTheData(){

            data.PutData();
            System.out.println("INFO :: Producer :: Just put data");
    }
}
 import java.util.Observable;
 import java.util.Observer;
 import java.util.Stack;
 import java.util.concurrent.atomic.AtomicReference;

 public class Consumer implements Observer {
    DataStorage data;
    MainProcess tempmp;
    public Consumer(DataStorage dst, MainProcess mp){
        data = dst;
        tempmp = mp;
    }


 public void update(Observable arg0, Object arg1) {
    System.out.println("INFO :: class is " + arg1.getClass().toString());
    System.out.println("INFO :: Consumer :: data is " + ((AtomicReference<Double>)arg1).get());


}
}
 import java.util.Observable;
 import java.util.concurrent.atomic.AtomicReference;

 public class DataStorage extends Observable {

   int countofdata;
   AtomicReference<Double> data = new AtomicReference<Double>();

   public DataStorage() {
       countofdata = 0;

   }

   public AtomicReference<Double> GetData() {

       // System.out.println("Data poped out:" + temp);
       countofdata--;
       return data;

   }

   public synchronized void PutData() {

      this.data.set(Math.random());
      System.out.println("INFO :: DataStorage :: Data inserted in storage:" + this.data.get());
      this.setChanged();
      this.notifyObservers(data);
      countofdata++;

  }
 }
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MainProcess implements Runnable{

/**
 * @param args
 */
DataStorage processData;
private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
private Producer p1, p2, p3, p4;
private Consumer c1, c2, c3, c4;

public MainProcess(){

    processData = new DataStorage();
    p1 = new Producer(processData, this);
    p2 = new Producer(processData, this);
    p3 = new Producer(processData, this);
    c1 = new Consumer(processData, this);
    c2 = new Consumer(processData, this);
    c3 = new Consumer(processData, this);
    processData.addObserver(c1);
    processData.addObserver(c2);
    processData.addObserver(c3);


}
public void startprocess(){
     this.scheduledExecutorService.scheduleAtFixedRate(this, 5, 10, TimeUnit.SECONDS);

}
public static void main(String[] args) {
    // TODO Auto-generated method stub
    MainProcess mp1 = new MainProcess();
    mp1.startprocess();

}
public void run() {
    System.out.println("INFO :: p1 Changing the data");
    p1.changeTheData();
    System.out.println("INFO :: p2 Changed the data");
    p2.changeTheData();
    System.out.println("INFO :: p3 Changed the data");
    p3.changeTheData();
}

}