Java面试题_多线程



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);

		}
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值