Java实现--线程间通信问题案例
来源:互联网 发布:百度鹰眼轨迹数据 编辑:程序博客网 时间:2024/06/05 07:08
案例:给学生设置和获取姓名和年龄。
案例分析:我们把学生对象作为一个资源进行操作,利用设置线程给学生对象设置姓名和年龄,利用获取线程获取姓名和年龄。
图解:
可以看出这是一个单生产单消费问题。
代码实现:
Student – 被设置的资源对应的类
package com.edu_01;public class Student { String name; int age;}
SetThread – 设置线程
package com.edu_01;public class SetThread extends Thread{ private Student s; private int x=0; public SetThread(Student s){ this.s=s; } @Override public void run() { while (true) { synchronized (s) { if (x%2==0) { s.name="张三"; s.age=22; } else { s.name="李四"; s.age=23; } x++; } } }}
GetThread – 获取线程
package com.edu_01;public class GetThread extends Thread{ private Student s; public GetThread(Student s){ this.s=s; } @Override public void run() { while (true) { synchronized (s) { System.out.println(s.name+":"+s.age); } } }}
StudnetDemo – 测试类
package com.edu_01;public class StudentDemo { public static void main(String[] args) { //创建学生对象 Student s = new Student(); //创建设置线程和获取线程并开启 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); st.start(); gt.start(); }}
运行结果:
这个案例实现过程中遇到的问题:
(1)打印null–0:
原因:设置和获取不是同一个对象,在设置线程和获取线程中new了两次,所以创建了两个学生对象。
解决:当在不同的类中,需要使用同一个数据的时候,可以考虑将数据利用构造方法进行传参。
(2)出现数据错乱,线程安全问题:
原因:是多线程情况;存在共享数据;存在多条语句对共享数据进行操作。所以存在线程安全问题。
解决:同步代码块,加锁。设置线程和获取线程,加的锁必须是同一个。
(3)打印的结果不够和谐:
原因:上面那个代码开启测试类后,会开启两个线程,一个是设置线程,一个是获取线程,然而我们并没有决定让谁抢到CPU的执行权。
对于第三个问题,我们可以使用等待唤醒机制来改进,实现礼让效果。
等待唤醒机制用到的几个方法:
wait()//让该线程处于等待状态notify()//唤醒等待的线程,如果没有线程在等待,则不起作用notifyAll()//唤醒所有等待的线程
注意:这几个方法都只能通过锁对象调用,只有在同步的时候,这几个方法才有效果。
改进后的代码:
Student – 被设置的资源对应的类
package com.edu_02;public class Student { String name; int age; boolean flag;//用来判断对象中是否有数据}
SetThread – 设置线程
package com.edu_02;public class SetThread implements Runnable{ private Student s; private int x=0; public SetThread(Student s){ this.s=s; } @Override public void run() { while (true) { synchronized (s) { //判断此时对象中有没有数据 if (s.flag) { try { s.wait();//设置线程等待,同时释放锁s } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (x%2==0) { s.name="张三"; s.age=22; } else { s.name="李四"; s.age=33; } x++; s.flag=true;//此时对象中有数据了 s.notify();//唤醒正在等待的线程,如果没有线程等待则没有任何效果 } } }}
GetThread – 获取线程
package com.edu_02;public class GetThread implements Runnable{ private Student s; public GetThread(Student s){ this.s=s; } @Override public void run() { while (true) { synchronized (s) { //判断对象中是否有数据 if (!s.flag) { try { s.wait();//获取线程等待,释放锁s } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(s.name+":"+s.age); s.flag=false;//当获取线程从对象中获取数据后,我们默认对象中没有数据了,此时我们应该让设置线程继续给学生对象设置学生信息 s.notify(); } } }}
StudnetDemo – 测试类
package com.edu_02;public class StudentDemo { public static void main(String[] args) { //创建学生对象 Student s = new Student(); //创建设置线程和获取线程 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); Thread t1 = new Thread(st); Thread t2 = new Thread(gt); //开启线程 t1.start(); t2.start(); }}
运行结果:
对上面代码继续优化:
(1)私有化Student类的成员变量
(2)在类的内部提供设置和获取的同步方法
代码实现:
Student – 被设置的资源对应的类
package com.edu_03;public class Student { //私有化成员变量 private String name; private int age; private boolean flag;//用来标记学生对象中是否有信息 //提供公共方法设置信息 public synchronized void setInfo(String name,int age){ if (this.flag) { try { this.wait();//等待 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //如果学生对象中没有信息,则设置信息 this.name=name; this.age=age; //更改标记,唤醒线程 this.flag=true; this.notify(); } //提供公共方法获取信息 public synchronized void getInfo(){ if (!this.flag) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //如果学生对象中有信息,则获取信息 System.out.println(this.name+":"+this.age); //更改标记,唤醒线程 this.flag=false; this.notify(); }}
SetThread – 设置线程
package com.edu_03;public class SetThread implements Runnable{ private Student s; private int x=0; public SetThread(Student s){ this.s=s; } @Override public void run() { while (true) { if (x%2==0) { s.setInfo("张三",22); } else { s.setInfo("李四",33); } x++; } }}
GetThread – 获取线程
package com.edu_01;public class GetThread implements Runnable{ private Student s; public GetThread(Student s){ this.s=s; } @Override public void run() { while (true) { s.getInfo(); } }}
StudnetDemo – 测试类
package com.edu_03;public class StudentDemo { public static void main(String[] args) { //设置学生对象 Student s = new Student(); //创建设置线程和获取线程 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); Thread t1 = new Thread(st); Thread t2 = new Thread(gt); //开启线程 t1.start(); t2.start(); }}
运行结果:
- Java实现--线程间通信问题案例
- JAVA线程间通信问题
- JAVA线程间通信问题
- Java多线程之死锁与线程间通信简单案例
- Java——线程间通信问题
- Java里如何实现线程间通信?
- Java里如何实现线程间通信?
- 2 Java 里实现线程间通信
- Java 里如何实现线程间通信
- Java 里如何实现线程间通信?
- Java 里如何实现线程间通信
- Java 里如何实现线程间通信
- Java 里如何实现线程间通信?
- Java 里如何实现线程间通信
- Java 里如何实现线程间通信
- Java 里如何实现线程间通信
- Java 里如何实现线程间通信
- Java 里如何实现线程间通信
- webpack完整教程(一)
- Spring_MVC前段数据验证,Validater验证器
- 测试CPU字节序,Chack CPU endian
- BrainFuck语言的解释器(java实现)
- Java 多态中的类型转换(instanceof)
- Java实现--线程间通信问题案例
- python3+ 和 Python2+的一些区别
- Solr+MMSEG4J的简单学习
- # 企业级开发基础:面向对象
- 学习 shell —— 编写基本脚本
- Java面试题全集(下)
- Stacktrace:] with root cause java.lang.NullPointerException 【jsp】
- 第6章 输入输出
- java程序员38道常规面试题