今天上午,参加大摩的面试,自觉失败,记录一下过程。
面试官看着简历,并没有就简历提问,整个过程都在问java多线程的问题。
1. ReentrantLock,作为可重入锁,怎么理解“可重入”二字,有没有不可重复的锁?
我:获得对象锁的线程能够再次获得对象锁,访问对象……被鄙视了,后来想想,应该把递归这种场景说下;
2.生产者-消费者模型怎么实现?
我:使用synchronized或者Lock这些同步方法实现。
面试官就问,为什么不用一些更高级的封装呢?
我:可以使用Exchanger类。
面试官:用BlockingQueue也可以,接下来,
3.作为一个接口,它有哪些具体的实现类?如何实现一个BlockingQueue,请实现它?
我:不清楚具体实现(后来查了下,有ArrayBlockingQueue,LinkedBlockingQueue,PriorityBlockingQueue,DelayQueue,SynchronousQueue,前两个最常见)。
可以使用List来存储数据,使用Lock与Condition来保证同步,代码如下(最好使用模板),
public class DefinedBlockingQueue {
private LinkedList queue;
private Lock lock;
private int max;
private Condition empty;
private Condition full;
public DefinedBlockingQueue(LinkedList queue, int max) {
this.queue = queue;
this.max = max;
lock = new ReentrantLock();
full = lock.newCondition();
empty = lock.newCondition();
}
public Integer take() {
lock.lock();
Integer t = null;
try {
while (queue.isEmpty()) {
full.await();
}
t = queue.poll();
empty.signalAll();
return t;
} catch (InterruptedException e) {
// e应该做处理
} finally {
lock.unlock();
}
return t;
}
public void put(Integer t) {
lock.lock();
try {
while (queue.size() == max) {
empty.await();
}
queue.add(t);
full.signalAll();
} catch (InterruptedException e) {
// e应该做处理
} finally {
lock.unlock();
}
}
}
4. 为什么使用Condition和Lock而不是synchronized和wait()来实现BlockingQueue()?
我:前者具有更好的特性,比如tryLock、读写锁等。
后来我又查了资料,补充:
Lock接口支持更灵活的同步代码块结构:使用synchronized关键字时,只能在同一个synchronized块结构中获取和释放控制。
Lock接口允许实现更复杂的临界区结构(控制的获取和释放不出现在同一个块结构中),比如ArrayBlockingQueue类的
void removeAt(int i) {
final Object[] items = this.items;
// if removing front item, just advance
if (i == takeIndex) {
items[takeIndex] = null;
takeIndex = inc(takeIndex);
} else {
// slide over all others up through putIndex.
for (;;) {
int nexti = inc(i);
if (nexti != putIndex) {
items[i] = items[nexti];
i = nexti;
} else {
items[i] = null;
putIndex = i;
break;
}
}
}
--count;
notFull.signal();
}