legendmohe 2010-07-25 18:33
浏览 257
已采纳

关于多线程通讯地一个疑问

[size=large]新手学JAVA,学到多线程,编了一个简单地电脑城进出货模拟系统。
代码有点长,主要部分如下所述:
有三方:厂家,电脑城,顾客
厂家2个,一个生产主板,一个生产显卡。
顾客有2个,他们各自不断购买主板和显卡。
电脑城有一个,卖显卡和主板。[/size]
限于篇幅问题,摘录主要代码如下:
--------------------------[b]厂家类[/b]---------------------------------------
[code="java"]public class Mainboardretailer implements Runnable// 主板厂家
{

public void run()
{
while(true)
{
电脑城.stockMainboard(deliverMB("MSI"));//不断向电脑城供货
}
}

public Mainboard deliverMB(String 主板名)
{
    return 主板;
}

}
public class Videocardretailer implements Runnable// 显卡厂家
{

public void run()
{
while(true)
{
电脑城.stockVideocard(deliverVC("ATI"));//不断向电脑城供货
}
}
public videocard deliverMB(String 显卡名)
{
return 显卡;
}

}[/code]
-------------------------------------[b]顾客类[/b]-------------------------------------------
[code="java"]public class customer implements Runnable
{
public void run()
{
while(true)
{
buyVC("ATI");
//顾客不断购买显卡和主板
buyMB("MSI");
}
}

}[/code]
-----------------------------[b]电脑城类[/b]-----------------------------------------
[code="java"]public class ComputerCenter
{
int MAXVCSTORE = 100;//货仓容量
int MAXMBSTORE = 100;//货仓容量
private static LinkedList VideocardQty = new LinkedList();//显卡货仓
private static LinkedList MainboardQty = new LinkedList();//主板货仓

public synchronized void stockVideocard(Videocard VCname)
{
    if(VideocardQty.size() >= MAXVCSTORE)
    {
        System.out.println("ComputerCenter: the VC storage is MAX");
        try 
        {
            wait();//---------------------当存货过多时。通知厂商等待。
        } catch (InterruptedException e) 
        {
            e.printStackTrace();
        }
    }
        VideocardQty.add(VCname);
        notify();//----------------------------唤醒消费者消费
}

public synchronized void stockMainboard(Mainboard MBname)
{
    if(MainboardQty.size() >= MAXVCSTORE)
    {
        System.out.println("ComputerCenter: the MB storage is MAX");
        try 
        {
            wait();//----------------------当存货过多时。通知厂商等待。
        } catch (InterruptedException e) 
        {
            e.printStackTrace();
        }
    }
        MainboardQty.add(MBname);
        notify();//-----------------------------唤醒消费者消费
}

public synchronized Videocard sellVideocard(String VCname)
{
    if(VideocardQty.size() <= 0)
    {
        try
        {
            wait();//-----------------没有存货时,通知消费者等待
        }catch(Exception e)
        {
            e.printStackTrace();
        }
    }
        notify();//----------------------------------唤醒厂商
        return MyVideocard;
}

public synchronized Mainboard sellMainboard(String MBname)
{
    if(MainboardQty.size() <= 0)
    {
        try
        {
            wait();//-----------------没有存货时,通知消费者等待
        }catch(Exception e)
        {
            e.printStackTrace();
        }
    }
        notify();//----------------------------------唤醒厂商
        return MyMainboard;
}

public static void main(String[] args)
{
    ComputerCenter MyCC = new ComputerCenter();
    new customer(MyCC,"Jack").start();
    new customer(MyCC,"Tom").start();
    new Mainboardretailer(MyCC).start();
    new Videocardretailer(MyCC).start();
}

}[/code]

[size=large]现在出现了这样的一个问题:
1.如果有两个消费者同时等待,厂家生产后唤醒其中消费者A,消费者A购买完毕后会唤醒消费者B--不合逻辑。
2.如果购买显卡地消费者A在等待,电脑城从主板厂商进货了主板以后会唤醒消费者A。同样的情况也发生在购买主板的消费者B身上。
3.如果两家厂商在等待消费者购买商品,此时消费者A购买了主板,货仓主板数量-1,然后有可能唤醒显卡厂商而没有唤醒主板厂商进行生产。
4.如果两家厂商正在等待消费者购买商品,此时显卡厂商被唤醒后,可能立刻唤醒主板厂商生产主板,令到商品数量超出仓库上限。[/size]

我想,有没有什么办法,可以[b]指定唤醒某个线程[/b]?如果可以,那问题就容易解决了。

  • 写回答

6条回答 默认 最新

  • hareamao 2010-07-26 21:31
    关注

    没怎么写过多线程,拿来练练手,未必正确。

    [code="java"]
    public class Product {
    private String name;
    private int serial;

    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getSerial() {
        return serial;
    }
    
    public void setSerial(int serial) {
        this.serial = serial;
    }
    

    }
    [/code]
    [code="java"]
    import java.util.ArrayDeque;

    public class StockManager {
    private final Object producerLock = new Object();
    private final Object consumerLock = new Object();
    private final int MAX_SIZE = 10;

    private final ArrayDeque<Product> queue = new ArrayDeque<Product>();
    
    public void stock(Product p) throws InterruptedException {
        synchronized (producerLock) {
            if (queue.size() >= MAX_SIZE) {
                producerLock.wait();
            }
        }
        synchronized (queue) {
            queue.add(p);
        }
        synchronized (consumerLock) {
            consumerLock.notify();
        }
    }
    
    public synchronized Product purchase() throws InterruptedException {
        synchronized (consumerLock) {
            if (queue.size() <= 0) {
                consumerLock.wait();
            }
        }
        Product product = null;
        synchronized (queue) {
            product = queue.remove();
        }
        synchronized (producerLock) {
            producerLock.notify();
        }
        return product;
    }
    

    }
    [/code]
    [code="java"]
    import java.util.logging.Logger;

    public class Producer implements Runnable{
    private static final Logger log = Logger.getLogger(Producer.class.getName());

    private String productName = null;
    private int serial = 0;
    private StockManager stockManager;
    
    public void setProductName(String productName) {
        this.productName = productName;
    }
    
    public void setStockManager(StockManager stockManager) {
        this.stockManager = stockManager;
    }
    
    public Product produce() {
        final Product p = new Product();
        p.setName(productName);
        p.setSerial(++serial);
        return p;
    }
    
    @Override
    public void run() {
        try {
            for( int i = 0; i < 20; i++) {
                deliver();
            }
            Thread.sleep(30 * 1000);
            while (true) {
                deliver();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    private void deliver() throws InterruptedException {
        final long s = System.currentTimeMillis();
        final Product product = produce();
        stockManager.stock(product);
        final long time = System.currentTimeMillis() - s;
        if (time > 10) {
            log.info(product.getName() + ", No. " +
                    product.getSerial() + " took " +
                    time + " milli seconds to finish." );
        }
    }
    

    }
    [/code]
    [code="java"]
    import java.util.logging.Logger;

    public class Consumer implements Runnable {
    private static final Logger log = Logger.getLogger(Consumer.class.getName());

    private String name;
    private StockManager[] stockManagers;
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void setStockManagers(StockManager[] stockManagers) {
        this.stockManagers = stockManagers;
    }
    
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            final double v = Math.random() * stockManagers.length;
            final int k = (int) Math.floor(v);
            try {
                final long s = System.currentTimeMillis();
                final Product product = stockManagers[k].purchase();
                final long time = System.currentTimeMillis() - s;
                String l = "";
                if (time > 10) {
                    l += "after " + time + " milli seconds of waiting, ";
                }
                l += (name + " bought product " + product.getName()
                        + ", serial No. " + product.getSerial());
                log.info(l);
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
    
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
        }
    }
    

    }
    [/code]
    [code="java"]
    public class Mall {
    public static void main(String[] args) {
    final StockManager mb = new StockManager();
    final Producer pmb = new Producer();
    pmb.setProductName("Motherboard");
    pmb.setStockManager(mb);

        final StockManager vd = new StockManager();
        final Producer pvd = new Producer();
        pvd.setProductName("Video Card");
        pvd.setStockManager(vd);
    
        final StockManager[] stockManagers = new StockManager[2];
        stockManagers[0] = mb;
        stockManagers[1] = vd;
    
        final Consumer c1 = new Consumer();
        c1.setName("C1");
        c1.setStockManagers(stockManagers);
    
        final Consumer c2 = new Consumer();
        c2.setName("C2");
        c2.setStockManagers(stockManagers);
    
        new Thread(c1).start();
        new Thread(c2).start();
    
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        new Thread(pmb).start();
        new Thread(pvd).start();
    }
    

    }
    [/code]

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(5条)

报告相同问题?

悬赏问题

  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置