线程安全的多个生产者问题

时间:2013-06-22 16:49:44

标签: java multithreading concurrency semaphore

我在现实生活中遇到了一个有趣的问题。我把问题简化到了这里:

设计两个方法A()和方法B()。每种方法都可以被认为是产生元素原子(A或B)。化合物A [N] B [M]需要N个A原子和M个B原子。

在我们有N个A原子和M个B原子之前,每个对A()和B()的调用都将被阻止。当我们到达N个A原子和M个B原子时,第一个N A()调用和第一个M B()调用将返回。例如,如果我进行N + 2个A()调用并遵循M B()调用,则将返回前N A()个调用和所有M B()调用。将有2个A()呼叫被阻止?

我该如何解决这个问题?我正在使用Java。

1 个答案:

答案 0 :(得分:1)

您可以使用 BlockingQueues

static class AtomA
{       
}

static class AtomB
{       
}

static class ChemicalCompound
{
    BlockingQueue<AtomA> as = new LinkedBlockingQueue<AtomA>();
    BlockingQueue<AtomB> bs = new LinkedBlockingQueue<AtomB>();

    public ChemicalCompound(int na, int nb)
    {
        while (na-- != 0) as.add(new AtomA());
        while (nb-- != 0) bs.add(new AtomB());
    }

    public AtomA A() throws InterruptedException
    {
        return as.take();
    }

    public AtomB B() throws InterruptedException
    {
        return bs.take();
    }
}

public static void main(String[] args) throws Exception
{       
    final ChemicalCompound cc = new ChemicalCompound(2, 3);

    Thread ta = new Thread(new Runnable(){
        @Override
        public void run()
        {
            while (true)
            {
                try
                {
                    cc.A();
                    System.out.println("Got a A!");
                    Thread.sleep(100);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }           
    });
    ta.start();

    Thread tb = new Thread(new Runnable(){
        @Override
        public void run()
        {
            while (true)
            {
                try
                {
                    cc.B();
                    System.out.println("Got a B!");
                    Thread.sleep(100);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }           
    });
    tb.start();

    ta.join();
    tb.join();

    return;
}

Thread.sleep 仅用于演示可能的线程交错,但当然“在生产中”将其删除。

结果:

Got a A!
Got a B!
Got a A!
Got a B!
Got a B!