多线程代码练习

  《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的设置一定要小心,起始与变换……

  就是这样了。 

 

 

posted @ 2011-01-29 00:36  汲月.Jr  阅读(1278)  评论(0编辑  收藏  举报