多线程2--毕向东基础视频教程学习笔记

Day12多线程:

1.线程间通信-示例代码

2.线程间通信-解决安全问题

3.线程间通信-等待唤醒机制

4.线程间通信-代码优化

5.线程间通信-生产者消费者

 

 

1.线程间通信-示例代码

线程间通信:

其实就是多个线程在操作同一个资源,

但操作的动作不同。

示例代码:

 1 class Res  2  2 {  3  3 String name;  4  4 String sex;  5  5     
 6  6 }  7  7 class Input implements Runnable  8  8 {  9  9     int x=0; 10 10     private Res r; 11 11     public Input(Res r) 12 12 { 13 13         this.r=r; 14 14 
15 15 } 16 16     public void run() 17 17 { 18 18         while(true) 19 19 { 20 20             if(x==0) 21 21 { 22 22             r.name="Mike"; 23 23             r.sex="man"; 24 24 } 25 25         else
26 26 { 27 27             r.name="黎黎"; 28 28             r.sex="女女女"; 29 29             
30 30 } 31 31         x=(x+1)%2; 32 32 
33 33 } 34 34     
35 35 
36 36 } 37 37 } 38 38 class Output implements Runnable 39 39 { 40 40     private Res r; 41 41     public Output(Res r) 42 42 { 43 43         this.r=r; 44 44 } 45 45     public void run() 46 46 { 47 47         while(true) 48 48 { 49 49             System.out.println(r.name+"---"+r.sex); 50 50 
51 51 } 52 52 
53 53 } 54 54 } 55 55 public class InputOutputDemo 56 56 { 57 57     public static void main(String[] args) 58 58 { 59 59         Res r=new Res(); 60 60         Output out=new Output(r); 61 61         Input in=new Input(r); 62 62 
63 63         Thread t1=new Thread(in); 64 64         Thread t2=new Thread(out); 65 65 
66 66 t1.start(); 67 67 t2.start(); 68 68 } 69 69 }
View Code

 

运行:

多线程2--毕向东基础视频教程学习笔记_第1张图片

出现了错误的输出。

 

2.线程间通信-解决安全问题 

解决方法:

从两个方面考虑:

1.是否是多线程

2.是否用同一把锁。

改动后:

 1 class Res  2 {  3  String name;  4  String sex;  5     
 6 }  7 class Input implements Runnable  8 {  9     int x=0; 10     private Res r; 11     public Input(Res r) 12  { 13         this.r=r; 14 
15  } 16     public void run() 17  { 18         while(true) 19  { 20                         //添加同步代码块,使用对象r作为锁
21 
22             synchronized(r) 23  { 24                 if(x==0) 25  { 26             r.name="Mike"; 27             r.sex="man"; 28  } 29         else
30  { 31             r.name="黎黎"; 32             r.sex="女女女"; 33             
34  } 35 
36  } 37             
38         x=(x+1)%2; 39 
40  } 41     
42 
43  } 44 } 45 class Output implements Runnable 46 { 47     private Res r; 48     public Output(Res r) 49  { 50         this.r=r; 51  } 52     public void run() 53  { 54         while(true) 55  { 56                         //添加同步代码块,使用对象r作为锁
57             synchronized(r) 58  { 59                 System.out.println(r.name+"---"+r.sex); 60 
61  } 62             
63 
64  } 65 
66  } 67 } 68 public class InputOutputDemo 69 { 70     public static void main(String[] args) 71  { 72         Res r=new Res(); 73         Output out=new Output(r); 74         Input in=new Input(r); 75 
76         Thread t1=new Thread(in); 77         Thread t2=new Thread(out); 78 
79  t1.start(); 80  t2.start(); 81  } 82 }
View Code

运行:

多线程2--毕向东基础视频教程学习笔记_第2张图片

不再有错误的输出,但是输出显示大片大片的男,大片大片的女。 

 

3.线程间通信-等待唤醒机制

要实现男女交替输出的效果,要用到wait和notify方法。

wait()

notify()

notifyAll()

都是用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中

只有同步才具有锁。

 

为什么这些操作线程的方法要定义在Object中呢?

因为这些方法在操作同步中的线程时,都必须标识它们所操作的线程持有的锁,

只有一个锁上的等待线程,可以被同一个锁上的notify唤醒。

不可以对不同锁上的线程进行唤醒。

 

也就是说,等待和唤醒必须是同一个锁。

而锁可以是任意对象,而可以被任意对象调用的方法定义在Object中。

修改后:

 1 class Res  2 {  3  String name;  4  String sex;  5     //定义布尔型标志位
 6     boolean flag=false;  7     
 8 }  9 class Input implements Runnable 10 { 11     int x=0; 12     private Res r; 13     public Input(Res r) 14  { 15         this.r=r; 16 
17  } 18     public void run() 19  { 20         while(true) 21  { 22             synchronized(r) 23  { 24                 //判断标志位,是否等待
25                 if(r.flag) 26                 {try{r.wait();}catch(Exception e){}} 27                 if(x==0) 28  { 29             r.name="Mike"; 30             r.sex="man"; 31  } 32         else
33  { 34             r.name="黎黎"; 35             r.sex="女女女"; 36             
37  } 38         //改变flag值
39         r.flag=true; 40         //唤醒
41  r.notify(); 42 
43  } 44             
45         x=(x+1)%2; 46 
47  } 48     
49 
50  } 51 } 52 class Output implements Runnable 53 { 54     private Res r; 55     public Output(Res r) 56  { 57         this.r=r; 58  } 59     public void run() 60  { 61         while(true) 62  { 63             synchronized(r) 64  { 65                    //判断标志位,是否等待
66                 if(!r.flag) 67                     try{r.wait();}catch(Exception e){} 68                 System.out.println(r.name+"---"+r.sex); 69                         r.flag=false; 70                         //唤醒
71  r.notify(); 72 
73  } 74             
75 
76  } 77 
78  } 79 } 80 public class InputOutputDemo 81 { 82     public static void main(String[] args) 83  { 84         Res r=new Res(); 85         Output out=new Output(r); 86         Input in=new Input(r); 87 
88         Thread t1=new Thread(in); 89         Thread t2=new Thread(out); 90 
91  t1.start(); 92  t2.start(); 93  } 94 }
View Code

 

运行:

多线程2--毕向东基础视频教程学习笔记_第3张图片

 

4.线程间通信-代码优化

数据私有化,通过方法访问。

优化后代码:

 1 class Res  2 {  3     //数据成员设置为私有
 4     private String name;  5     private String sex;  6     //定义布尔型标志位
 7     private boolean flag=false;  8     
 9     //定义set、get同步方法
10     public synchronized void set(String name,String sex) 11  { 12         if(flag) 13                 {try{this.wait();}catch(Exception e){}} 14         this.name=name; 15         this.sex=sex; 16 
17         flag=true; 18         this.notify(); 19  } 20     public synchronized void get() 21  { 22         if(!flag) 23                 {try{this.wait();}catch(Exception e){}} 24         System.out.println(name+"---"+sex); 25 
26         flag=false; 27         this.notify(); 28  } 29     
30 } 31 class Input implements Runnable 32 { 33     int x=0; 34     private Res r; 35     public Input(Res r) 36  { 37         this.r=r; 38 
39  } 40     public void run() 41  { 42         while(true) 43  { 44                 if(x==0) 45  { 46             //调用set方法
47             r.set("Mike","man"); 48  } 49            else
50  { 51             r.set("黎黎","女女女"); 52             
53  } 54         x=(x+1)%2; 55  } 56     
57 
58  } 59 } 60 class Output implements Runnable 61 { 62     private Res r; 63     public Output(Res r) 64  { 65         this.r=r; 66  } 67     public void run() 68  { 69         while(true) 70  { 71             //调用get方法
72  r.get(); 73  } 74 
75  } 76 } 77 public class InputOutputDemo 78 { 79     public static void main(String[] args) 80  { 81         Res r=new Res(); 82         //简化
83         new Thread(new Input(r)).start(); 84         new Thread(new Output(r)).start(); 85 
86     
87  } 88 }
View Code

 

5.线程间通信-生产者消费者

当有多个生产者,多个消费者时,必须循环判断标记,以避免产生生产2个,只消费了一个或类似的情况;

并且使用notifyAll方法,以避免出现所有线程都在等待的情况。

 1 class Resource  2 {  3     private String name;  4     private int count=1;  5     private boolean flag=false;  6 
 7     public synchronized void set(String _name)  8  {  9         while(flag) 10  { 11             try{wait();}catch(Exception e){} 12  } 13         name=_name+"--"+count++; 14         System.out.println(Thread.currentThread().getName()+"--生产者"+name); 15         flag=true; 16  notifyAll(); 17 
18  } 19     public synchronized void get() 20  { 21         while(!flag) 22  { 23             try{wait();}catch(Exception e){} 24  } 25         System.out.println(Thread.currentThread().getName()+"--------消费者"+name); 26         flag=false; 27  notifyAll(); 28 
29  } 30 } 31 class Producer implements Runnable 32 { 33     private Resource r=new Resource(); 34     public Producer(Resource r) 35  { 36         this.r=r; 37  } 38     public void run() 39  { 40         while(true) 41  { 42             r.set("商品"); 43  } 44  } 45 } 46 class Consumer implements Runnable 47 { 48     private Resource r=new Resource(); 49     public Consumer(Resource r) 50  { 51         this.r=r; 52  } 53     public void run() 54  { 55         while(true) 56  { 57  r.get(); 58  } 59  } 60 } 61 public class ProducerConsumerDemo 62 { 63     public static void main(String[] args) 64  { 65         Resource r=new Resource(); 66 
67         Producer pro=new Producer(r); 68         Consumer con=new Consumer(r); 69 
70         Thread t1=new Thread(pro); 71         Thread t2=new Thread(pro); 72         Thread t3=new Thread(con); 73         Thread t4=new Thread(con); 74 
75  t1.start(); 76  t2.start(); 77  t3.start(); 78  t4.start(); 79 
80  } 81 }
View Code

运行:

多线程2--毕向东基础视频教程学习笔记_第4张图片

 

你可能感兴趣的:(多线程2--毕向东基础视频教程学习笔记)