原文:http://blog.csdn.net/qingfengliuquan/article/details/5891187
编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推 这是一道迅雷的笔试题
总结下方法
1. 最佳的方法 用java.util.concurrent.Semaphore 信号量
- package quiz;
- import java.util.concurrent.Semaphore;
- public class SemaphoreABC {
- static class T extends Thread{
- Semaphore me;
- Semaphore next;
- public T(String name,Semaphore me,Semaphore next){
- super(name);
- this.me = me;
- this.next = next;
- }
- @Override
- public void run(){
- for(int i = 0 ; i < 10 ; i ++){
- try {
- me.acquire();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(this.getName());
- next.release();
- }
- }
- }
- public static void main(String[] args) {
- Semaphore aSem = new Semaphore(1);
- Semaphore bSem = new Semaphore(0);
- Semaphore cSem = new Semaphore(0);
- T a = new T("A",aSem,bSem);
- T b = new T("B",bSem,cSem);
- T c = new T("C",cSem,aSem);
- a.start();
- b.start();
- c.start();
- }
- }
2. 用wait 和 notify 实现 同样借鉴了 信号量的思想,自己在上面的启发下改的
- package quiz;
- /**
- *
- *
- * <p>
- * Title: 迅雷笔试的测验
- * </p>
- * <p>
- * Description: 把abc 看做是三盏灯,循环亮,三个开关控制三个灯的,三个人代表三个线程 每次先看前一盏灯的亮灯的情况
- * 在看自己的情况,决定是否亮灯,然后将亮灯的消息通知给下个人
- * </p>
- * <p>
- * Copyright: Copyright (c) 2007-2010
- * </p>
- * <p>
- * Company:
- * </p>
- *
- * @author
- * @version 1.0 2010-9-17
- */
- public class RunableThread1 implements java.lang.Runnable {
- // 内部开关类 isLighting=true 表示灯开
- private class Switch {
- public Switch(boolean printedSingal) {
- this.isLighting = printedSingal;
- }
- public boolean isLighting;
- }
- // a灯的开关
- Switch aSwitch = new Switch(false);
- // b灯的开关
- Switch bSwitch = new Switch(false);
- // c灯的开关 初始化 默认为开着,这样下次a灯才能亮
- Switch cSwitch = new Switch(true);
- public void run() {
- // TODO Auto-generated method stub
- for (int i = 0; i < 10; i++) {
- // 如果是A线程
- if (Thread.currentThread().getName().equals("A")) {
- // 总是先去看前一盏灯的状态后,在决定是否轮到自己亮了
- // A去申请控制等c灯的开关,如果此时c的开关空闲,A锁住开关,防止他人摆弄
- synchronized (cSwitch) {
- // 轮询上一盏灯c,如果c一直灭着,则等待,由于我们已经默认初始化c亮着
- // 故不会死锁
- while (!cSwitch.isLighting) {
- try {
- // 等着c亮的好消息
- cSwitch.wait();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- // c终于亮了,该哥a亮了 先打印出自己
- System.out.print(Thread.currentThread().getName());
- // 关掉c灯
- cSwitch.isLighting = false;
- // A去申请控制等a灯的开关,如果此时a的开关空闲,A锁住开关,防止他人摆弄
- synchronized (aSwitch) {
- // a灯亮了
- aSwitch.isLighting = true;
- // 将a灯亮的消息通知给B
- aSwitch.notify();
- }
- }
- } // B线程上场了,同上
- else if (Thread.currentThread().getName().equals("B")) {
- synchronized (aSwitch) {
- while (!aSwitch.isLighting) {
- try {
- aSwitch.wait();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- System.out.print(Thread.currentThread().getName());
- aSwitch.isLighting = false;
- synchronized (bSwitch) {
- bSwitch.isLighting = true;
- bSwitch.notify();
- }
- }
- } else if (Thread.currentThread().getName().equals("C")) {
- synchronized (bSwitch) {
- while (!bSwitch.isLighting) {
- try {
- bSwitch.wait();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- System.out.print(Thread.currentThread().getName());
- bSwitch.isLighting = false;
- synchronized (cSwitch) {
- cSwitch.isLighting = true;
- cSwitch.notify();
- }
- }
- }
- }
- }
- public static void main(String[] args) {
- RunableThread1 rt = new RunableThread1();
- Thread aThread = new Thread(rt, "A");
- Thread bThread = new Thread(rt, "B");
- Thread cThread = new Thread(rt, "C");
- aThread.start();
- bThread.start();
- cThread.start();
- }
- }
3. 同样用用wait 和 notify 实现 ,别人成果,自己加入了自己的理解
- package quiz;
- public class RunableThread2 implements java.lang.Runnable {
- private class Switch {
- public Switch(boolean printedSingal) {
- this.isLighting = printedSingal;
- }
- public boolean isLighting;
- }
- Switch aSwitch = new Switch(false);
- Switch bSwitch = new Switch(false);
- Switch cSwitch = new Switch(false);
- public void run() {
- // TODO Auto-generated method stub
- for (int i = 0; i < 10; i++) {
- if (Thread.currentThread().getName().equals("A")) {
- synchronized (cSwitch) {
- System.out.print(Thread.currentThread().getName());
- synchronized (aSwitch) {
- aSwitch.isLighting = true;
- aSwitch.notify();
- }
- while (!cSwitch.isLighting) {
- try {
- cSwitch.wait();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- cSwitch.isLighting = false;
- //
- }
- } else if (Thread.currentThread().getName().equals("B")) {
- synchronized (aSwitch) {
- while (!aSwitch.isLighting) {
- try {
- aSwitch.wait();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- System.out.print(Thread.currentThread().getName());
- aSwitch.isLighting = false;
- synchronized (bSwitch) {
- bSwitch.isLighting = true;
- bSwitch.notify();
- }
- }
- } else if (Thread.currentThread().getName().equals("C")) {
- synchronized (bSwitch) {
- while (!bSwitch.isLighting) {
- try {
- bSwitch.wait();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- System.out.print(Thread.currentThread().getName());
- bSwitch.isLighting = false;
- synchronized (cSwitch) {
- cSwitch.isLighting = true;
- cSwitch.notify();
- }
- }
- }
- }
- }
- public static void main(String[] args) {
- RunableThread2 rt = new RunableThread2();
- Thread aThread = new Thread(rt, "A");
- Thread bThread = new Thread(rt, "B");
- Thread cThread = new Thread(rt, "C");
- aThread.start();
- bThread.start();
- cThread.start();
- }
- }
总结:
1.java 高级的concurrent包很强大,写复杂的控制很有用
2. 这个题目对理解wait 和notify 很有用,自己写了 才发现,看着是一回事 ,写又是另一回事情
3. 很多时候 特别要注意死锁,自己因为abc的打印 陷入了思路死锁很长时间,自己比较笨,呵呵,一定要给出初始化条件用来解除死锁(如程序2),或者条件判断避免死锁(如程序3),这个需要破除思维定势等。
4. 形象的思维很重要,synchronized (chair){} 想象为 某人去申请椅子,
如果椅子有人坐了,则阻塞自己,在while{里循环chair.wait()} ,直到有人通知 chair.notify() 你他要离开椅子,你方能去申请椅子
如果没人坐,先坐上,锁住椅子,防止别人坐,同时在椅子上做些事情,比如看书啥的,做完了,千万别忘了chair.notify() 别人。