Java面试题_多线程
前段时间换工作,碰到一道面试题,当时没答出来,贴出来记录一下。
1 题目
使用两个线程,打印出 线程1-1,线程1-2,线程1-3,线程2-4,线程2-5,线程2-6,。。。,直到打印到30个为止。
2 解答
2.1解答1
使用主线程控制两个线程,线程1和线程2,让其分别打印。
初始时,线程1和线程2初始等待状态
主线程通知线程1运行,1运行完毕后,通知2运行。
线程1在this的调用wait,主线程要保证线程1处于等待状态才能通知其运行,不然运程1会一直处于等待状态。
OneByOnePrint 是主线程控制类,ThreadPrint是打印线程。
new OneByOnePrint(startNum, count, perThread).doPrint();
public static class OneByOnePrint {
private ThreadPrint r1;
private ThreadPrint r2;
private int maxNum;
private int perThread;
private int startNum;
public OneByOnePrint(int startNum, int maxNum, int perThread) {
this.r1 = new ThreadPrint();
this.r2 = new ThreadPrint();
this.maxNum = maxNum;
this.perThread = perThread;
this.startNum = startNum;
this.r1.count = perThread;
this.r2.count = perThread;
}
private void doPrint() {
new Thread(r1).start();
new Thread(r2).start();
ThreadPrint current;
for (int i = 0; i < maxNum; i = i + perThread) {
if (i % 2 == 0) {
current = r1;
} else {
current = r2;
}
// 等待其处于等待状态
waited(current);
current.startNum = startNum + i;
// 通知打印
current.notifyForPrint();
// 等待其处于等待状态 再处理下一个线程
waited(current);
}
r1.runFlag = false;
r2.runFlag = false;
waited(r1);
waited(r2);
r1.notifyForPrint();
r2.notifyForPrint();
}
/**
* 等待线程处于等待状态
*
* @param current
*/
private void waited(ThreadPrint current) {
while (!current.haveWaited()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static class ThreadPrint implements Runnable {
private int startNum;
private int count;
private volatile boolean haveWaited = false;
private volatile boolean runFlag = true;
@Override
public void run() {
while (true) {
waitForPrint();
if (!runFlag)
break;
for (int i = 0; i < count; i++) {
p(startNum + i);
}
}
}
public boolean haveWaited() {
synchronized (this) {
return haveWaited;
}
}
private void waitForPrint() {
synchronized (this) {
haveWaited = true;
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void notifyForPrint() {
synchronized (this) {
haveWaited = false;
this.notify();
}
}
private void p(int i) {
System.out.println("Thread Name "
+ Thread.currentThread().getName() + ":" + i);
}
}
2.2 解答2
可以然线程1,线程2组成一个双向链表,这样可以灵活支持多个线程打印。
上代码
new OneByOnePrint2(startNum, count, perThread).doPrint();
public static class OneByOnePrint2 {
private int maxNum;
private int perThread;
private int startNum;
private int increment;
private int threadCount;
public OneByOnePrint2(int startNum, int maxNum, int perThread) {
this(startNum, 1, maxNum, 2, perThread);
}
public OneByOnePrint2(int startNum, int increment, int maxNum,
int threadCount, int perThread) {
this.startNum = startNum;
this.increment = increment;
this.maxNum = maxNum;
this.threadCount = threadCount;
this.perThread = perThread;
}
private void doPrint() {
LinkedList<ThreadPrint2> queue = new LinkedList<ThreadPrint2>();
ThreadPrint2 pre = null, cur = null;
for (int i = 0; i < threadCount; i++) {
cur = new ThreadPrint2(this.maxNum, this.perThread,
this.increment, queue);
cur.startNum = this.startNum;
if (pre != null) {
cur.previsPrint = pre;
pre.nextPrint = cur;
new Thread(cur, "线程" + i).start();
}
pre = cur;
queue.add(cur);
}
new Thread(queue.get(0), "线程0").start();
}
}
public static class ThreadPrint2 implements Runnable {
private volatile int startNum;
private int count;
private int maxNum;
private volatile boolean haveWaited = false;
private ThreadPrint2 nextPrint;
private ThreadPrint2 previsPrint;
private volatile LinkedList<ThreadPrint2> queue;
private int currentNum;
private int increment;
public ThreadPrint2(int maxNum, int perThread, int increment,
LinkedList<ThreadPrint2> queue2) {
this.maxNum = maxNum;
this.count = perThread;
this.increment = increment;
this.queue = queue2;
}
@Override
public void run() {
boolean runflag = true;
while (runflag) {
// 不是第一个线程就等待上一个线程
waitForPrevis();
// 从等待中唤醒
haveWaited = false;
// 删除队列头
queuePop();
// 打印
runflag = printInfo();
// 唤醒下一个线程
notifyNextPrint(runflag);
}
}
private void notifyNextPrint(boolean runflag) {
if (nextPrint != null) {
ThreadPrint2 next = nextPrint;
next.startNum = getNextNum(currentNum);
asurewaited(next);
// 如果有可能要运行 加入到对尾
if (runflag) {
queueEnd();
}
this.notifyForPrint();
}
}
private int getNextNum(int preNum) {
return preNum + this.increment;
}
private boolean printInfo() {
currentNum = startNum;
for (int i = 0; i < count; i++) {
if (i == 0)
currentNum = startNum;
else
currentNum = getNextNum(currentNum);
if (currentNum > maxNum) {
return false;
}
printOne(currentNum);
}
return true;
}
private void queueEnd() {
ThreadPrint2 end = queue.getLast();
end.nextPrint = this;
this.previsPrint = end;
this.nextPrint = null;
queue.offer(this);
}
private void queuePop() {
queue.poll();
}
private void asurewaited(ThreadPrint2 t) {
while (!t.haveWaited()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 是否处于等待状态 防止后续线程还没有处于等待状态就发出的通知
*
* @return
*/
public boolean haveWaited() {
synchronized (previsPrint) {
return haveWaited;
}
}
/**
* 等待前一个线程
*/
private void waitForPrevis() {
if (previsPrint != null) {
synchronized (previsPrint) {
haveWaited = true;
try {
previsPrint.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void notifyForPrint() {
synchronized (this) {
this.notify();
}
}
private void printOne(int i) {
System.out.println("Thread Name "
+ Thread.currentThread().getName() + ":" + i);
}
}