多线程代码练习
《Java开发实战经典》中多线程的练习只有两道,为了恢复自己的编程能力,我特意做了做两道题。当我做完第一题的时候以为自己的感觉回来了,谁知道做了第二道题我才明白,自己对于多线程的“交通灯”模式根本不懂。
这里的“交通灯”模式即是处理“生产者”与“消费者”之间同步协调的问题。哪知道一个看似简单的flag,就把我弄的晕头转向了……
C++中有全局变量这个东西,可是,Java不能做到这个,Java是纯面向对象的语言,一切都是对象,所以……当我对书上的代码产生疑问时想自己写,一切调试无误之后,运行时Object.wait()却抛出一个异常……鸟懂……于是乎,只得去听从孔老夫子的教诲:“思而不学,则殆矣!”
第二天看了看书,一直感觉这个代码很不合理,书上的例子是这样的:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 };
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,有了以下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
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的设置一定要小心,起始与变换……
就是这样了。