Featured image of post 阿里面试题分享(二)

阿里面试题分享(二)

这道题由于是从网上看到的,具体出自阿里哪个部门不详。题目描述:使用“生产者-消费者模式”编写代码实现:线程A

Image

这道题由于是从网上看到的,具体出自阿里哪个部门不详。

题目描述:

使用“生产者-消费者模式”编写代码实现:线程A随机间隔(10~200ms)按顺序生成1到100的数字(共100个),放到某个队列中。

线程B、C、D即时消费这些数据:

  • 线程B消费所有被3整除的数,

  • 线程C消费所有被5整除的数,

  • 其它的由线程D进行消费。

线程BCD消费这些数据时在控制台中打印出来, 要求按顺序打印这些数据。限时40分钟,可以查API

这里有一个网友的答案:

我的答案:

  1package com.oho.alg;
  2
  3import java.util.PrimitiveIterator.OfLong;
  4import java.util.Random;
  5import java.util.concurrent.BlockingQueue;
  6import java.util.concurrent.TimeUnit;
  7import lombok.SneakyThrows;
  8
  9public class Producer implements Runnable {
 10
 11  private BlockingQueue<Integer> queue;
 12
 13  private OfLong longs = new Random().longs(10, 200).iterator();
 14
 15  public Producer(BlockingQueue<Integer> queue) {
 16
 17    this.queue = queue;
 18
 19  }
 20
 21  @SneakyThrows
 22  @Override
 23  public void run() {
 24
 25    for (int i = 1; i <= 100; i++) {
 26
 27      queue.put(i);
 28      System.out.println("生产了:" + i);
 29
 30      try {
 31        TimeUnit.MILLISECONDS.sleep(longs.nextLong());
 32      } catch (InterruptedException e) {
 33        e.printStackTrace();
 34      }
 35
 36    }
 37
 38  }
 39
 40}
 41
 42package com.oho.alg;
 43
 44import java.util.concurrent.ArrayBlockingQueue;
 45import java.util.concurrent.BlockingQueue;
 46import java.util.concurrent.locks.Condition;
 47import java.util.concurrent.locks.Lock;
 48import java.util.concurrent.locks.ReentrantLock;
 49
 50public class Consumer {
 51
 52  private Lock lock = new ReentrantLock();
 53  
 54  private Condition cc3 = lock.newCondition();
 55  private Condition cc5 = lock.newCondition();
 56  private Condition ccn = lock.newCondition();
 57
 58  private BlockingQueue<Integer> queue;
 59
 60  public Consumer(BlockingQueue<Integer> queue) {
 61
 62    this.queue = queue;
 63
 64  }
 65
 66  public void c3() {
 67
 68    try {
 69      lock.lock();
 70
 71      while (true) {
 72
 73        if (queue.peek() != null) {
 74
 75          while (queue.peek() % 3 != 0) {
 76            cc3.await();
 77
 78          }
 79          System.out.println("消费3的倍数: " + queue.poll());
 80          cc5.signal();
 81          ccn.signal();
 82
 83        }
 84      }
 85    } catch (Exception e) {
 86      e.printStackTrace();
 87    } finally {
 88      lock.unlock();
 89    }
 90
 91  }
 92
 93  public void c5() {
 94
 95    try {
 96      lock.lock();
 97
 98      while (true) {
 99
100        if (queue.peek() != null) {
101
102          while (queue.peek() % 5 != 0) {
103            cc5.await();
104          }
105          System.out.println("消费5的倍数: " + queue.poll());
106          cc3.signal();
107          ccn.signal();
108
109        }
110      }
111    } catch (Exception e) {
112      e.printStackTrace();
113    } finally {
114      lock.unlock();
115    }
116
117  }
118
119  public void other() {
120
121    try {
122      lock.lock();
123
124      while (true) {
125
126        if (queue.peek() != null) {
127
128          while (queue.peek() % 3 == 0 || queue.peek() % 5 == 0) {
129            ccn.await();
130          }
131
132          System.out.println("消费other倍数: " + queue.poll());
133          cc3.signal();
134          cc5.signal();
135
136        }
137      }
138    } catch (Exception e) {
139      e.printStackTrace();
140    } finally {
141      lock.unlock();
142    }
143
144  }
145
146  public static void main(String[] args) throws InterruptedException {
147
148    ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(100);
149    Consumer consumer = new Consumer(queue);
150    new Thread(new Producer(queue)).start();
151    new Thread(() -> consumer.c3()).start();
152    new Thread(() -> consumer.c5()).start();
153    new Thread(() -> consumer.other()).start();
154
155  }
156}

这题看起来挺简单的,但实际写的时候还是有一些点需要注意,尤其是对condition的使用。

Image

synchronized与wait()和nitofy()/notifyAll()方法相结合可以实现等待/通知模型,ReentrantLock同样可以,但是需要借助Condition,且Condition有更好的灵活性,具体体现在:

1、一个Lock里面可以创建多个Condition实例,实现多路通知

2、notify()方法进行通知时,被通知的线程是Java虚拟机随机选择的,但是ReentrantLock结合Condition可以实现有选择性地通知,这是非常重要的

Image

关注公众号 获取更多精彩内容

位旅人路过 次翻阅 初次见面