关于多线程的面试题

题目:子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着又回到主线程又循环100次,如此循环50次。写出程序。

1、思路:

这是一道考察多线程的题目。应题目的要求,子线程循环10次和主线程循环100次的中途不能被打断,则需要在循环方法里面加入互斥锁。要连续有规律运行主线程和子线程,可以考虑当线程执行完一个周期的循环后,让线程休眠让出线程运行权,或者使用wita()和notify()方法。

2、答案之一:

public class TranditionThreadCommunication {
	public static void main(String[] args) {

		final Business business = new Business();

		// 子线程循环
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 1; i <= 50; i++) {
					try {
						business.sub(i);
					} catch (InterruptedException e) {
					}
				}
			}
		}).start();

		// 主线程循环
		for (int i = 1; i <= 50; i++) {
			try {
				business.mian(i);
			} catch (InterruptedException e) {
			}
		}

	}
}

/**
 * 业务类型(包含各色的同步锁)
 */
class Business {
	// sub()方法是否该运行标识
	private boolean bShouldSub = true;

	/**
	 * 循环100次打印的方法sub()
	 * 
	 * @param i
	 * @throws InterruptedException
	 */
	public synchronized void sub(int i) throws InterruptedException {
		while (!bShouldSub) { // 当 bShouldSub 为 false 时,则等待
			this.wait();
		}
		for (int j = 1; j <= 10; j++) {
			System.out.println("sub thread :   第" + i + "行, 第" + j + "列");
		}
		bShouldSub = false; // 执行for循环后,标志sub()方法不可再执行
		this.notify(); // 唤醒线程
	}

	/**
	 * 循环100次打印的方法mian()
	 * 
	 * @param i
	 * @throws InterruptedException
	 */
	public synchronized void mian(int i) throws InterruptedException {
		while (bShouldSub) {
			this.wait();
		}
		for (int j = 1; j <= 100; j++) {
			System.out.println("main thread :   第" + i + "行, 第" + j + "列");
		}
		bShouldSub = true; // 执行for循环后,标志sub()方法可再执行了
		this.notify(); // 唤醒线程
	}
}

3、经验:

(1)要用到共同数据(包括同步锁)或共同算法的若干个方法应该归在同一个类身上,这种设计体现了高类聚和程序的健壮性。像上面的循环10次和循环100次的操作都需要用到锁时,可以将这两个方法加上锁(synchronized)并放到Business类中。

(2)上面答案中的

	while (bShouldSub) {
			this.wait();
		}

借鉴了javaAPI 中的wait()方法的写法,主要是为了防止线程之间可能出现的伪唤醒。

java API 中的wait()方法的原文如下:

public final void wait() throws InterruptedException 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。 当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。

对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:

synchronized (obj) {
    while (<condition does not hold>)
        obj.wait();
     // Perform action appropriate to condition
}

此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。 抛出: IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。 InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,任何线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。

猜你喜欢

转载自my.oschina.net/u/3696939/blog/1819217
今日推荐