多线程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 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

运行:

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

 

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

 

运行:

 

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

运行:

 

原文地址:https://www.cnblogs.com/wsw-tcsygrwfqd/p/5005911.html