《Java开发实战经典》中多线程的练习只有两道,为了恢复自己的编程能力,我特意做了做两道题。当我做完第一题的时候以为自己的感觉回来了,谁知道做了第二道题我才明白,自己对于多线程的“交通灯”模式根本不懂。
这里的“交通灯”模式即是处理“生产者”与“消费者”之间同步协调的问题。哪知道一个看似简单的flag,就把我弄的晕头转向了……
C++中有全局变量这个东西,可是,Java不能做到这个,Java是纯面向对象的语言,一切都是对象,所以……当我对书上的代码产生疑问时想自己写,一切调试无误之后,运行时Object.wait()却抛出一个异常……鸟懂……于是乎,只得去听从孔老夫子的教诲:“思而不学,则殆矣!”
第二天看了看书,一直感觉这个代码很不合理,书上的例子是这样的:
代码 1 class Info{ // 定义信息类 2 private String name = " 李兴华 " ; // 定义name属性 3 private String content = " JAVA讲师 " ; // 定义content属性 4 private boolean flag = false ; // 设置标志位 5 public synchronized void set(String name,String content){ 6 if ( ! flag){ 7 try { 8 super .wait() ; 9 } catch (InterruptedException e){ 10 e.printStackTrace() ; 11 } 12 } 13 this .setName(name) ; // 设置名称 14 try { 15 Thread.sleep( 300 ) ; 16 } catch (InterruptedException e){ 17 e.printStackTrace() ; 18 } 19 this .setContent(content) ; // 设置内容 20 flag = false ; // 改变标志位,表示可以取走 21 super .notify() ; 22 } 23 public synchronized void get(){ 24 if (flag){ 25 try { 26 super .wait() ; 27 } catch (InterruptedException e){ 28 e.printStackTrace() ; 29 } 30 } 31 try { 32 Thread.sleep( 300 ) ; 33 } catch (InterruptedException e){ 34 e.printStackTrace() ; 35 } 36 System.out.println( this .getName() + 37 " --> " + this .getContent()) ; 38 flag = true ; // 改变标志位,表示可以生产 39 super .notify() ; 40 } 41 public void setName(String name){ 42 this .name = name ; 43 } 44 public void setContent(String content){ 45 this .content = content ; 46 } 47 public String getName(){ 48 return this .name ; 49 } 50 public String getContent(){ 51 return this .content ; 52 } 53 }; 54 class Producer implements Runnable{ // 通过Runnable实现多线程 55 private Info info = null ; // 保存Info引用 56 public Producer(Info info){ 57 this .info = info ; 58 } 59 public void run(){ 60 boolean flag = false ; // 定义标记位 61 for ( int i = 0 ;i < 50 ;i ++ ){ 62 if (flag){ 63 this .info.set( " 李兴华 " , " JAVA讲师 " ) ; // 设置名称 64 flag = false ; 65 } else { 66 this .info.set( " mldn " , " www.mldnjava.cn " ) ; // 设置名称 67 flag = true ; 68 } 69 } 70 } 71 }; 72 class Consumer implements Runnable{ 73 private Info info = null ; 74 public Consumer(Info info){ 75 this .info = info ; 76 } 77 public void run(){ 78 for ( int i = 0 ;i < 50 ;i ++ ){ 79 this .info.get() ; 80 } 81 } 82 }; 83 public class ThreadCaseDemo03{ 84 public static void main(String args[]){ 85 Info info = new Info(); // 实例化Info对象 86 Producer pro = new Producer(info) ; // 生产者 87 Consumer con = new Consumer(info) ; // 消费者 88 new Thread(pro).start() ; 89 new Thread(con).start() ; 90 } 91 };
其中Info类做了太多的事,而这部分事本应该是由“生产者”和“消费者”类做的。
联系中是说要把Info换成电脑。我简单点儿,就把电脑的属性抽象成一个编号Num,有了以下代码:
代码 1 class Comp { 2 private int num = 0 ; 3 static boolean flag = false ; 4 public synchronized void setNum( int num) { 5 if (flag) { // 仅是在此处加入了等待与唤醒 6 try { 7 super .wait(); 8 } catch (InterruptedException e) { 9 e.printStackTrace(); 10 } 11 } 12 this .num = num; 13 flag = true ; 14 super .notify(); 15 } 16 public synchronized int getNum() { 17 if ( ! flag) { // 同上 18 try { 19 super .wait(); 20 } catch (InterruptedException e) { 21 e.printStackTrace(); 22 } 23 } 24 flag = false ; 25 super .notify(); 26 return this .num; 27 } 28 } 29 class CompPro implements Runnable { 30 private Comp comp = null ; 31 private static int cout = 0 ; 32 public CompPro(Comp comp) { 33 this .comp = comp; 34 } 35 public synchronized void run() { 36 int i; 37 for (i = 0 ; i <= 50 ; i ++ ) { 38 try { 39 Thread.sleep( 100 ); // 设置不同的睡眠时间以测试 40 } catch (InterruptedException e) { 41 e.printStackTrace(); 42 } 43 comp.setNum(cout); 44 cout ++ ; 45 } 46 } 47 } 48 class CompSell implements Runnable { 49 private Comp comp = null ; 50 public CompSell(Comp comp) { 51 this .comp = comp; 52 } 53 public synchronized void run() { 54 int i; 55 for (i = 0 ; i <= 50 ; i ++ ) { 56 try { 57 Thread.sleep( 15 ); // 设置不同的睡眠时间以测试 58 } catch (InterruptedException e) { 59 e.printStackTrace(); 60 } 61 System.out.println(comp.getNum()); 62 } 63 } 64 } 65 public class Comps { 66 public static void main(String[] args) { 67 Comp c = new Comp(); 68 CompPro pro = new CompPro(c); 69 CompSell sell = new CompSell(c); 70 new Thread(pro).start(); 71 new Thread(sell).start(); 72 } 73 }
调试了很久,终于成功了,其中大家要是真看了代码的话,对于flag的设置一定要小心,起始与变换……
就是这样了。
转载于:https://www.cnblogs.com/mooner-hw/archive/2011/01/29/1947322.html
相关资源:java基础多线程练习题(1)