FizzBu​​zz多线程消费者制作人

时间:2017-08-10 20:52:34

标签: java multithreading

我有几个线程(生产者和消费者)的FizzBu​​zz问题 我在网上找到了这个解决方案:https://gist.github.com/masudak/5098917 但我担心一个特定的情况,一个糟糕的上下文切换,其中'isStop'  是的,但并非所有生产者都将他们的数字添加到队列中。 这是一个真正的问题吗?或者我错过了什么?

public static AtomicInteger counter = new AtomicInteger(0);
public static ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<Integer>();
public static volatile boolean isStop = false; 

public static class Producer implements Runnable{

    @Override
    public void run() {
        while ( true ) {
            Integer counterValue = counter.incrementAndGet();
            if (counterValue <= 100) {
                queue.add(counterValue);
            } else {
                isStop = true;
                break;
            }
        }
    }   
}

public static class Consumer implements Runnable{

    @Override
    public void run() {
        while ( true ) {
            Integer counterValue = queue.poll();
            if ( counterValue == null ){
                if(isStop){
                    break;
                }
                continue;
            }

            fizzBuzz(counterValue);
        }
    }


    private void fizzBuzz(Integer value){
        if( value % 15 == 0 ){
            System.out.println("FizzBuzz:" + value);
        } else if( value % 3 == 0 ){
            System.out.println("Fizz:" + value);
        } else if( value % 5 == 0 ){                
            System.out.println("Buzz:" + value );
        } else {
            System.out.println(value);
        }
    }   
}

1 个答案:

答案 0 :(得分:0)

尽管格式错误和其他问题,这是恕我直言,实际上是一个有趣的问题。是的,我相信这段代码包含一个理论问题,尽管这个问题难以揭露。但是,如果通过添加一些显式随机Thread.sleep来修改代码,这将模拟真实世界任务的不同线程性能的意外差异,您可以轻松地看到此问题。然后重现问题,您只需要3个线程:2 Producer s和一个Consumer s。同样重要的是,在sleep Producer速度增加后,Consumer的速度变得比单Consumer的速度慢得多(与Producerimport java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; public class fizzbuzz { public static void main(String[] args) { Thread th1 = new Thread(new Producer()); Thread th2 = new Thread(new Producer()); Thread th4 = new Thread(new Consumer()); th1.start(); th2.start(); th4.start(); } public static AtomicInteger counter = new AtomicInteger(0); public static ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<Integer>(); public static volatile boolean isStop = false; public static class Producer implements Runnable { @Override public void run() { while (true) { Integer counterValue = counter.incrementAndGet(); final int MAX = 10; if (counterValue <= MAX) { final int sleep = ThreadLocalRandom.current().nextInt(200); try { Thread.sleep(sleep); } catch (InterruptedException e) { e.printStackTrace(); } queue.add(counterValue); } else { isStop = true; break; } } } } public static class Consumer implements Runnable { @Override public void run() { while (true) { Integer counterValue = queue.poll(); if (counterValue == null) { if (isStop) { break; } continue; } fizzBuzz(counterValue); } } private void fizzBuzz(Integer value) { if (value % 15 == 0) { System.out.println("FizzBuzz:" + value); } else if (value % 3 == 0) { System.out.println("Fizz:" + value); } else if (value % 5 == 0) { System.out.println("Buzz:" + value); } else { System.out.println(value); } } } } 被阻止的原始代码不同/ {操作isStop s不是)。我还将最大值减小到10以缩短日志。所以这是代码:

isStop

如果您运行此代码几次,您可能会看到如下内容:

  

1   
2   
4   嘶嘶声:3   嘶嘶声:6   
嗡嗡声:5   
7   
8   
Buzz:10

请注意, 9 缺失。发生这种情况是因为生产者#9的睡眠不仅仅是生产者#10的睡眠,所以在实际添加所有元素之前都会isStop被提升。

甚至是这样的事情:

  

1   
2   嘶嘶声:3   
嗡嗡声:5   
4   嘶嘶声:6   
7   嘶嘶声:9   
8

注意缺少 10 。这是恕我直言,更有趣的是:生产者#9为队列和下一次迭代增加了价值,而生产者#10正在睡觉时提出TensorShape = namedtuple('TensorShape', ['batch_size', 'channels', 'height', 'width']) 标志,因为没有其他东西可以生成。

这类问题的一个明显的解决方法是使用CountDownLatch之类的东西来设置s = [hdr, '-' * 94] ... s.append('{:<20} {:<30} {:>20} {:>20}'.format(node.kind, node.name, data_shape, tuple(out_shape))) ,而不是在第一个生产者完成其工作时,而是在最后一个生产者完成工作时。