一道多线程编程面试题

2019-08-10  本文已影响0人  周群力

看到一道多线程面试题,看起来很简单但是仔细想想有些细节很容易踩坑,因此记录一下。

题目来源:https://juejin.im/post/5c89b9515188257e5b2befdd

题目:

评论:

这题用信号量数组、用Monitor(一个lock和condition数组)都能做。用信号量的解法上述链接里有,这里说下用Monitor解题存在的坑:

1. 如果代码写成了主线程初始化并start了所有线程后,直接condition.signal通知第一个线程,可能会存在问题:假如第一个线程还没有被调度、还没有执行condition.await,此时condition.signal会在condition.await之前执行,这次通知就丢掉了(但是信号量就可以先release再aquire,先通知再等待)所以为避免这种情况,还得加个countDownLatch保证所有线程的任务都执行过之后,主线程再获取锁、condition.signal通知第一个线程起跑;

2. 用condition.signal或await的前提是当前线程持有该锁(信号量就没有这种限制,可以看链接里给的信号量实现方案)

用Monitor解题的代码:

public class LoopPrinter {

private final PrintTask[]tasks;

private final int            number;

private final Thread[]threads;

private final ReentrantLocklock    =new ReentrantLock();

private final Condition[]conditions;

private      Integercounter = -1;

private final CountDownLatchinitedLatch;

public CountDownLatch getInitedLatch() {

return initedLatch;

}

public ReentrantLock getLock() {

return lock;

}

public Condition[] getConditions() {

return conditions;

}

public LoopPrinter(int number) {

if (number <=0) {

throw new IllegalArgumentException("The number must be positive.");

}

this.number = number;

threads =new Thread[number];

tasks =new PrintTask[number];

conditions =new Condition[number];

initedLatch =new CountDownLatch(number);

for (int i =0; i < number; i++) {

PrintTask printTask =new PrintTask(this, i);

tasks[i] = printTask;

threads[i] =new Thread(printTask);

conditions[i] =lock.newCondition();

}

}

public void start() {

for (int i =0; i

threads[i].start();

}

try {

initedLatch.await();

tasks[0].go();

}catch (InterruptedException e) {

e.printStackTrace();

}

}

public static void main(String[] args)throws InterruptedException {

LoopPrinter printer =new LoopPrinter(3);

printer.start();

Thread.sleep(3000);

}

private static class PrintTaskimplements Runnable {

private LoopPrinterprinter;

private int        index;

public PrintTask(LoopPrinter loopPrinter,int i) {

this.printer = loopPrinter;

index = i;

}

@Override

        public void run() {

//取锁

            printer.getLock().lock();

try {

while (true) {

Condition[] conditions =printer.getConditions();

printer.getInitedLatch().countDown();

Condition condition = conditions[index];

condition.await();

int counter =printer.increCounter();

if (counter >100) {

System.exit(0);

}

System.out.println("Thread " +index +":" + counter);

int nextIdx = (index +1) % conditions.length;

conditions[nextIdx].signal();

}

}catch (InterruptedException e) {

e.printStackTrace();

}finally {

printer.getLock().unlock();

}

}

public void go() {

printer.getLock().lock();

try {

Condition[] conditions =printer.getConditions();

Condition condition = conditions[index];

condition.signal();

}finally {

printer.getLock().unlock();

}

}

}

private int increCounter() {

counter +=1;

return counter;

}

}

上一篇下一篇

猜你喜欢

热点阅读