一道Java线程面试题。3个线程顺序打印10次ABC.

一道Java线程面试题。3个线程顺序打印10次ABC.
2011-06-12 00:30



原文出处http://hi.baidu.com/dapplehou/blog/item/14e62834ebe1bc235ab5f504.html


遇到一题,网上搜索一下,才知是流行已久的面试题。相信很多有心求职的同学都经常做流 行面试题备战各大公司面试吧。有点像应试备战。没做过这些题目练习的肯定要吃亏了。所 以很多公司为了避免走入应试误区也会采取一些除了这种客观笔试外的主观面试以考察应聘 者的真正解决问题的能力,以防止猜题、押宝。


题目描述:有三个线程名字分别是A、B、C,每个线程只能打印自己的名字,在屏幕上顺序打印 ABC,打印10次。不准使用线程的sleep()



第一,我自己的一个解法:
public class SwitchStatus extends Thread {
private static String currentThread = "A";
private static byte[] lock = new byte[0];
private String name = "";
private int count = 10;

public SwitchStatus(String name) {
this.name = name;
}

public void run() {
while (count > 0) {
synchronized (lock) {
if (currentThread.equals(this.name)) {
System.out.print(name);
count--;
if (currentThread.equals("A")) {
currentThread = "B";
} else if (currentThread.equals("B")) {
currentThread = "C";
} else if (currentThread.equals("C")) {
currentThread = "A";
System.out.println();
}
}
}
}
}

/**
* @param args
*/
public static void main(String[] args) {
(new SwitchStatus("A")).start();
(new SwitchStatus("B")).start();
(new SwitchStatus("C")).start();
}
}



第二,网上看到一个不错的解法:
public class MyThread extends Thread{
private static Object o = new Object();
private static int count = 0;
private char ID;
private int id;
private int num = 0;
public MyThread(int id, char ID) {
this.id = id;
this.ID = ID;
}

public void run() {
synchronized (o) {
while (num < 10) {
if (count % 3 == id) {
System.out.print(ID);
++count;
++num;

o.notifyAll();

}
else {
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
(new MyThread(0, 'A')).start();
(new MyThread(1, 'B')).start();
(new MyThread(2, 'C')).start();
}
}

这两种解法的思路是相似的。
对公共资源加锁,以阻塞其它线程。
用一个全局变量(3个线程都可访问的公共变量)控制状态 第一种解法的全局变量是:private static String currentThread = "A"; 第二种解法的全局变量是:private static int count = 0;配合count%3来控制状态。

对这道题来说,如果开动脑筋,好像有无穷无尽的解法。比如可以采用CyclicBarrier来进行 线程控制,关于CyclicBarrier的使用可参考http://hi.baidu.com/dapplehou/blog/item/0a4c65388143b72c96ddd814.html#sec-9



第三,下面,我使用CyclicBarrier来写一段这样的打印代码.
public class CycliBarrierTest implements Runnable {
private static List list = new ArrayList(3);
private CyclicBarrier barrier;
private String name ="";

public CycliBarrierTest(CyclicBarrier barrier,String name) {
this.barrier = barrier;
this.name = name;
}

public void run() {
//do xxxx;
try {
for(int i=0;i<10;i++){
list.add(name);
this.barrier.await();//线程运行至此会检查是否其它线程都到齐了,没到齐就继续等待。到齐了就执行barrier的run函数体里的内容
}
} catch (Exception e) {

}
}

/**
* @param args
*/
public static void main(String[] args) {
//参数3代表3个线程都达到起跑线才开始一起继续往下执行
CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() {
public void run() {
//do xxxx;
Collections.sort(list);
for(int i=0,n=list.size();i<n;i++){
System.out.print(list.get(i));
}
list.clear();
System.out.println();
}
});
Thread t1 = new Thread(new CycliBarrierTest(barrier,"A"));
Thread t2 = new Thread(new CycliBarrierTest(barrier,"B"));
Thread t3 = new Thread(new CycliBarrierTest(barrier,"C"));
t1.start();
t2.start();
t3.start();
}

}



第四,既然使用了java.util.concurrent包里的类,就不妨再使用这个包里的另一个类Semaphore. 即,用信号量作线程控制。

代码如下
public class SemaphoreThread extends Thread {
private Semaphore current;
private Semaphore next;
public SemaphoreThread(String name, Semaphore current, Semaphore next) {
super(name);
this.current = current;
this.next = next;
}
public void run() {
for (int i = 0; i < 10; i++) {
try {
current.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(this.getName());
next.release();
}
}

public static void main(String[] args) {
Semaphore a = new Semaphore(1);
Semaphore b = new Semaphore(0);
Semaphore c = new Semaphore(0);
new SemaphoreThread("A", a, b).start();
new SemaphoreThread("B", b, c).start();
new SemaphoreThread("C", c, a).start();

}
}



第五,还有其它方法吗?当然有。这次,我就试着用一个阻塞队列再写一个打印abc的程序。
public class BlockingQ extends Thread {
private static String currentThread = "A";
private static BlockingQueue<String> blockingQ = new ArrayBlockingQueue<String>(
1);
private String name = "";
private int count = 10;

public BlockingQ(String name) {
this.name = name;
}

@Override
public void run() {
while (count > 0) {
try {
blockingQ.put(name);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (currentThread.equals(this.name)) {
try {
System.out.print(blockingQ.take());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count--;
if (currentThread.equals("A")) {
currentThread = "B";
} else if (currentThread.equals("B")) {
currentThread = "C";
} else if (currentThread.equals("C")) {
currentThread = "A";
System.out.println();
}
}else{
try {
blockingQ.take();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
}

还有别的方法吗?肯定是有的。运用之妙存乎一心,如果感兴趣,就自己想想吧。



原作者联系方式

author: Dapple Hou

mail: mmonkeyer@163.com
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值