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

    xiaoxiao2021-03-25  67

    转载地址:http://www.cnblogs.com/wsw-tcsygrwfqd/p/5005911.html

    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 }

     

    运行:

    出现了错误的输出。

     

    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 }

    运行:

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

     

    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 }

     

    运行:

     

    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 }

     

    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 }

    运行:

     

    转载请注明原文地址: https://ju.6miu.com/read-35281.html

    最新回复(0)