java并发、生产者(代理)和消费者

java并发、生产者(代理)和消费者,java,multithreading,concurrency,Java,Multithreading,Concurrency,我需要关于使用并发的java分配的帮助。我遇到的问题是get方法,我找不到任何错误。然而,它感觉它没有被正确访问,或者它没有做它应该做的事情。总而言之,问题是我得到了所有的金属,但我没有给消费者任何,我不知道这是怎么发生的。如果我需要提供任何其他信息,请告诉我 每个经纪人都持有所有三种金属的库存,但只是其中一种金属的“供应商”,称为其“特产”。精炼商不时向作为其供应商的经纪人交付一批精炼金属。例如,精炼厂可能向黄金供应商交付30盎司黄金。消费者定期向经纪人下订单。每个订单指定每种金属的盎司数。它

我需要关于使用并发的java分配的帮助。我遇到的问题是
get
方法,我找不到任何错误。然而,它感觉它没有被正确访问,或者它没有做它应该做的事情。总而言之,问题是我得到了所有的金属,但我没有给消费者任何,我不知道这是怎么发生的。如果我需要提供任何其他信息,请告诉我

每个经纪人都持有所有三种金属的库存,但只是其中一种金属的“供应商”,称为其“特产”。精炼商不时向作为其供应商的经纪人交付一批精炼金属。例如,精炼厂可能向黄金供应商交付30盎司黄金。消费者定期向经纪人下订单。每个订单指定每种金属的盎司数。它可以放在任何经纪人那里。如果可能的话,经纪人将从自己的股票中填写订单。如果金属M的供应商因为手头没有足够的M而无法完成订单,那么它只需等待,直到从精炼厂获得更多。但如果它做空其他金属,它会试图通过与供应商交易该金属来获得它。为了简单起见,我们将假设(有些不切实际地)盎司的黄金、铂或铀都具有同等价值。也就是说,三盎司黄金可以换成三盎司铀或三盎司铂

很抱歉,我无法显示使用BrokerImplementation的类。我不能,因为它们都是.class文件,而且我不认为上传位代码会有任何帮助

提前感谢您提供的任何帮助

// This class overrides all it's methods from the Broker interface
public class BrokerImplementation implements Broker, IBM {

int specialty;
int[] metals = {0, 0, 0};

/**
 * The constructor takes a single integer parameter, the code for the metal
 * which this broker supplies.
 *
 * @param specialty
 */
public BrokerImplementation(int specialty) {
    this.specialty = specialty;
}

/**
 * This method is used by Project2.main to audit the global state when the
 * system shuts down. The Broker should fill in result with the amount of
 * each metal it has on hand. 
 *
 * @param result
 */
@Override
public void getAmountOnHand(int[] result) {

    //GOLD, PLATINUM, URANIUM are are constants in the IBM interface
    //which correspond to the indexes {0, 1, 2} 
    result[GOLD] = metals[GOLD];
    result[PLATINUM] = metals[PLATINUM];
    result[URANIUM] = metals[URANIUM];
}

/**
 * A consumer calls this method to place an order. The argument is a
 * three-element array indicating the number of ounces of gold, platinum,
 * and uranium desired. It should return only when the order has been
 * filled.
 *
 * @param metals
 */
@Override
public void get(int[] order) {

    for(int i = 0; i < 3; i++){
    if (metals[i] > order[i]) {
        metals[i] -= order[i];
    } else {
        this.swap(i, order[i] - metals[i]);
        this.get(order);
        try {
            wait();
        } catch (InterruptedException ex) {
            Logger.getLogger(BrokerImplementation.class.getName()).log(Level.SEVERE, null, ex);
        }
        notifyAll();
    }
    }
}

/**
 * Another broker calls this method to swap one metal for another. The what
 * argument indicates one of the metals; the other one is the metal in which
 * this broker specializes. The ounces argument indicates how many ounces to
 * swap.
 *
 * @param what
 * @param ounces
 */
@Override
public void swap(int what, int ounces) {

    synchronized (this) {
        if (metals[specialty] >= ounces) {

            metals[specialty] -= ounces;
            metals[what] += ounces;

        } else {
            notifyAll();
            try {
                wait();
            } catch (InterruptedException ex) {
                Logger.getLogger(BrokerImplementation.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
    }
}

/**
 * The refiner calls this method to deliver a load of metal to the broker.
 * The argument ounces is a number of ounces. The metal is the one this
 * broker supplies.
 *
 * @param ounces
 */
@Override
public void deliver(final int ounces) {
    System.out.println("available " + metals[specialty]);
    metals[specialty] += ounces;
}
//此类重写代理接口中的所有方法
公共类BrokerImplementation实现了Broker,IBM{
国际专业;
int[]金属={0,0,0};
/**
*构造函数接受单个整数参数,即金属的代码
*这个经纪人提供的。
*
*@param专业
*/
公共经纪实施(国际专业){
这个。专业=专业;
}
/**
*Project2.main使用此方法在
*系统关闭。代理应在结果中填写
*它手头的每一种金属。
*
*@param结果
*/
@凌驾
public void getamounthand(int[]结果){
//金、铂、铀是IBM界面中的常量
//它们对应于索引{0,1,2}
结果[金]=金属[金];
结果[铂]=金属[铂];
结果[铀]=金属[铀];
}
/**
*消费者调用此方法下单。参数为
*三元素数组,表示黄金、铂金、,
*和铀。它应该只在订单完成后返回
*填满了。
*
*@准金属
*/
@凌驾
公共无效获取(int[]顺序){
对于(int i=0;i<3;i++){
if(金属[i]>订单[i]){
金属[i]=订单[i];
}否则{
交换(i,订单[i]-金属[i]);
这个。得到(订单);
试一试{
等待();
}捕获(中断异常例外){
Logger.getLogger(BrokerImplementation.class.getName()).log(Level.SEVERE,null,ex);
}
notifyAll();
}
}
}
/**
*另一个经纪人调用此方法以将一种金属交换为另一种金属
*参数表示其中一种金属;另一种是其中的金属
*这个经纪人专门从事这项工作。盎司参数表示需要多少盎司
*交换。
*
*@param什么
*@param盎司
*/
@凌驾
公共无效掉期(整数什么,整数盎司){
已同步(此){
if(金属[特种]>=盎司){
金属[特殊]-=盎司;
金属[什么]+=盎司;
}否则{
notifyAll();
试一试{
等待();
}捕获(中断异常例外){
Logger.getLogger(BrokerImplementation.class.getName()).log(Level.SEVERE,null,ex);
}
}
}
}
/**
*精炼者调用此方法将金属负载交付给代理。
*参数盎司是一个盎司数。金属就是这个
*经纪用品。
*
*@param盎司
*/
@凌驾
公共无效交付(最终整数盎司){
系统输出打印(“可用”+金属[专业]);
金属[特种]+=盎司;
}

专门查看
get(int[]顺序)
method有几件事您没有考虑。由于您在问题中提到了多线程,我假设多个线程可以同时调用此方法。鉴于这一事实,您没有考虑对共享资源的同步访问
metals[]
。操作
-=
不是线程安全的,您在该数组上的迭代也不是线程安全的。此外,当您添加同步时,如果您关心性能,请尝试最小化同步内容,因为在
上同步大型块会影响性能


编辑:我还建议(尽管您没有要求这样做)在同步块中不要有wait()。这将导致死锁,因为同步块中的线程将阻塞
metals[]在等待的同时,

在此展开,您可能需要考虑对金属的访问而不是GET()的同步化。方法。我看到的问题是,您可以通过3种方式修改金属:获得交货、与供应商交换或填写订单。因为所有这些都可能同时发生,并且都引用相同的集合资源,即资源(金属)应该同步。另外,正如@nattyddubbs所说的,我会避免在方法上同步,因为它会在“this”上同步。相反,在特定的共享资源上执行尽可能小的同步块。我如何在金属上进行同步,如果我以前在金属上尝试过,但是