黑马程序员 ---- 线程间通信
来源:互联网 发布:怎样下载plc编程软件 编辑:程序博客网 时间:2024/05/21 17:34
------- android培训、java培训、期待与您交流! ----------
例1:问题的引出。(共享数据没有同步) 【误】class P{String name;String sex;}class Producer implements Runnable{P q = null;public Producer(P q){this.q = q;}public void run(){int i = 0;while(true){if(i==0){q.name = "Zhang";q.sex = "mail";}else{q.name = "LI";q.sex = "femail";}i = (i+1)%2;// 定义了一个切换代码,该表达式的值只能为 1 或 0 。在 if 和 else 之间切换。}}}class Consumer implements Runnable{P q = null;public Consumer(P q){this.q = q;}public void run(){while(true){System.out.println(q.name+"---------"+q.sex);}}}class Test{public static void main(String[] args){P k = new P();Producer i = new Producer(k);Consumer o = new Consumer(k);Thread t1 = new Thread(i);Thread t2 = new Thread(o);t1.start();t2.start();//new Thread(new Producer(q)).start();//new Thread(new Consumer(q)).start();}}
运行结果: 该程序有问题。 没有同步操作共享数据的代码。可能会出现 name 与 sex 不对应的情况。
例2: 问题的解决。(共享数据同步,加入睡眠唤醒机制,但代码没有优化) 【正】class P{String name;String sex;boolean flag = false;}class Producer implements Runnable{P q = null;public Producer(P q){this.q = q;}public void run(){int i = 0;while(true){synchronized(q) // 锁可以是 Producer.class 、 Consumer.class 、 q 、 Test.class 这些都是唯一的。{if(q.flag)try{q.wait();}catch(Exception e){}if(i==0){q.name = "Zhang";q.sex = "mail";}else{q.name = "LI";q.sex = "femail";}i = (i+1)%2;// 定义了一个切换代码,该表达式的值只能为 1 或 0 。在 if 和 else 之间切换。q.flag = true;q.notify();}}}}class Consumer implements Runnable{P q = null;public Consumer(P q){this.q = q;}public void run(){while(true){synchronized(q){if(!q.flag)try{q.wait();}catch(Exception e){}System.out.println(q.name+"---------"+q.sex);q.flag = false;q.notify();}}}}class Test{public static void main(String[] args){P k = new P();Producer i = new Producer(k);Consumer o = new Consumer(k);Thread t1 = new Thread(i);Thread t2 = new Thread(o);t1.start();t2.start();//new Thread(new Producer(q)).start();//new Thread(new Consumer(q)).start();}}
运行结果: 该程序正常运行,并得出正确结果。对应的两组 name 、 sex 交替出现。
范例分析: 1. wait(). notify(). notifyAll() 都是用在同步中,因为要对持有的监视器(锁)的线程操作。所以要使用在同步中,因为只有同步才具有锁。
2. 为什么这些操作线程的方法要定义 Object 类中呢
因为这些方法在操作同步中线程时,都必须要标识他们所操作的线程持有的锁,只有同一个锁上的被等待线程,才可以被同一个锁上notify唤醒。不可以
对不同锁中的线程唤醒, 也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object 类中。
例3: 代码优化。(优化代码,但只是用于一个消费者,一个生产者,多个消费者、生产者就不适用了) 【正】class P{private String name;private String sex;private boolean flag = false;public synchronized void set(String name, String sex){if(flag)try{wait();}catch(Exception e){}this.name = name;this.sex = sex;flag = true;this.notify();}public synchronized void out(){if(!flag)try{wait();}catch(Exception e){}System.out.println(name+"\t"+sex);flag = false;this.notify();}}class Producer implements Runnable{P q = null;public Producer(P q){this.q = q;}public void run(){int i = 0;while(true){if(i==0){q.set("zhang","mail");}else{q.set("LI","femail");}i = (i+1)%2;// 定义了一个切换代码,该表达式的值只能为 1 或 0 。在 if 和 else 之间切换。}}}class Consumer implements Runnable{P q = null;public Consumer(P q){this.q = q;}public void run(){while(true){q.out();}}}class Test{public static void main(String[] args){P q = new P();/*Producer i = new Producer(k);Consumer o = new Consumer(k);Thread t1 = new Thread(i);Thread t2 = new Thread(o);t1.start();t2.start();*/new Thread(new Producer(q)).start();new Thread(new Consumer(q)).start();}}
运行结果: 该程序正确,并得出正确结果。
范例分析: 优点: 在例2 的基础上采取了优化措施,并封装了代码私有后更简洁更安全。
缺点: 只是用于一个生产者,一个消费者。
例4:延续上个程序的需求,但要加入多个生产者和多个消费者.class P{private String name;private int count = 1;private boolean flag = false;public synchronized void set(String name){while(flag) // 此处用 while 循环是为了让判断过并在此等待的线程,在被唤醒时再判断一次,以免在唤醒时被同是生产者或同是消费者给唤醒。 try{wait();}catch(Exception e){}this.name = name+"....."+count++;System.out.println(Thread.currentThread().getName()+"-----Producer--------"+count);flag = true;this.notifyAll(); // 一个线程在执行完后,为了不唤醒被类中的线程,而让所有线程都被唤醒,让后用 while 再次判断是否该唤醒需要唤醒的线程。 // 当只有一个 Producer 和 一个 Consumer 时, 可以用 notify() ,而当有多个时,用 notifyAll(),来唤醒所有在等待的线程。 } // 如果这里使用 notify ,程序在运行一段时间后自动就停止了,因为没有被唤醒的线程没有执行权,而有执行权的线程却没被唤醒。public synchronized void out(){while(!flag)try{wait();}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"+++++++++++++Consumer+++++"+count);flag = false;this.notifyAll();}}class Producer implements Runnable{P q = null;public Producer(P q){this.q = q;}public void run(){int i = 0;while(true){q.set("水果糖");}}}class Consumer implements Runnable{P q = null;public Consumer(P q){this.q = q;}public void run(){while(true){q.out();}}}class Test{public static void main(String[] args){P q = new P();Producer p = new Producer(q);Consumer c = new Consumer(q);Thread t1 = new Thread(p); // 定义了四个生产者和四个消费者Thread t2 = new Thread(p);Thread t3 = new Thread(c);Thread t4 = new Thread(c);t1.start();t2.start();t3.start();t4.start();}}
运行结果: 该程序正确,并得出正确结果。
范例分析 ; 优点: 在例3的基础上让程序可以同时有多个生产者和多个消费者。
缺点: 不适用于一个消费者,一个生产者。
0 0
- 黑马程序员 ---- 线程间通信
- 黑马程序员_线程间的通信
- 黑马程序员:JAVA线程间的通信
- 黑马程序员-线程间的通信
- 黑马程序员-线程间的通信
- 黑马程序员---多线程:线程间通信
- 黑马程序员_<<线程间通信>>
- 黑马程序员_线程间的通信
- 黑马程序员---多线程、线程间通信
- 黑马程序员-day12-多线程(线程间通信)
- 黑马程序员-day12多线程-线程间通信
- 黑马程序员——线程间通信
- 黑马程序员-多线程--线程间的通信
- 黑马程序员--线程间的通信
- 黑马程序员---线程间通信、停止线程等
- 35.黑马程序员-线程间通信(生产者消费者)
- 黑马程序员__java基础之线程间通信
- 黑马程序员--第十二天:线程间的通信
- 游戏云间之六:数据安全
- 数学—杭电1405 The Last Practice
- 生物信息学简介 -整理综合
- Android在非UI主线程操作UI的简单方法
- Android智能指针分析(sp、wp)
- 黑马程序员 ---- 线程间通信
- Eclipse中,Open Type(Ctrl+Shift+T)失效后做法。
- opcache? Zend Optimizer强势来临
- 使用YUMI和BOOTICE在U盘上安装多系统
- ListPopupWindow使用完整示例(一)——系统自带ListPopupWindow
- HP 580G7的细节让人不省心,虽然官网有验证,但很容易被忽略。
- 学习笔记_linux——java程序部署
- 在网站中嵌入qq,msn等聊天框
- 分析函数