首页 > 代码库 > JAVA学习第二十六课(多线程(五))- 多线程间的通信问题
JAVA学习第二十六课(多线程(五))- 多线程间的通信问题
一、线程间的通信
实例代码:
需求是:输入一个姓名和性别后,就输出一个姓名和性别
class Resource { String name; String sex ; } class Input implements Runnable { Resource r; Input(Resource r) { this.r = r; } public void run() { int x = 0; while(true) { synchronized (r) { if(x==0) { r.name = "BLF"; r.sex = "male"; } else { r.name = "妮妮妮妮"; r.sex = "female"; } x = (++x)%2; } } } } class Output implements Runnable { Resource r; public Output(Resource r) { // TODO Auto-generated constructor stub this.r = r; } public void run() { while(true) { synchronized (r) //输入和输出都是应用同一个锁 { System.out.println(r.name+"..."+r.sex); } } } } public class Main { public static void main(String[] args) { Resource r = new Resource();//共享同一资源 Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } }
上述代码虽然解决了,多线程处理同一资源问题,但是出现了一个问题就是,打印很多一个人名和性别后再打印另一个,无法实现交替输出,原因:输入线程获取执行权后,不会执行一次,输入姓名和性别,输入线程还拥有执行权,一直赋值,等到切换到输出执行权后,输出最后输入的姓名和性别,但是输出线程也不会只输出一次,一直输出,所以出现打印很多同一姓名和性别的问题
二、线程的等待/唤醒机制:
用一个boolean值判断是否有数据,有就不放,没有就放
输入线程执行时判断是否有数据,有,就释放执行权,再释放执行资格,进入冻结状态,输出线程执行,输出后boolean值置为false
Input: if(flag)//有值 wait();//当前冻结,切换输出线程 flag = true; notify(); Output: if(!flag) wait(); flag = false;//flag置为假,输出完毕 notify();//唤醒输入线程
等待/唤醒机制:
方法:
1.wait();//使线程进入冻结状态,CPU释放执行权和执行资格,被wait()的线程会被存储到线程池中 2.notify();//唤醒线程池中的任意的一个线程 3.notifyAll();//唤醒所有线程,使之处于运行状态或临时阻塞状态,总之,使其具备执行资格
这些方法必须定义在同步中,这些方法是用于操作线程状态的方法,所以必须明确在哪个锁上的线程
(wait()A锁的线程,只能用A锁的notify唤醒A锁的线程。)
了解:而wait()等方法是定义在Object类中的,这些方法是监视器的方法,而监视器呢,就可以理解为锁,控制哪个锁所属下的线程,而锁又可以是任意的,而所有的类都是继承于Object类的,所以wait()等类是定义在Object里
下述代码就解决了上述代码的问题,实现了输入输出线程的交替执行
class Resource extends Object { String name; String sex ; boolean flag = false; } class Input implements Runnable { Resource r; Input(Resource r) { this.r = r; } public void run() { int x = 0; while(true) { synchronized (r) { if(r.flag) { try { r.wait(); } catch (Exception e) { // TODO: handle exception } } if(x==0) { r.name = "BLF"; r.sex = "male"; } else { r.name = "妮妮妮妮"; r.sex = "female"; } r.flag = true; r.notify(); x = (++x)%2; } } } } class Output implements Runnable { Resource r; public Output(Resource r) { // TODO Auto-generated constructor stub this.r = r; } public void run() { while(true) { synchronized (r) { if(!r.flag) { try { r.wait(); } catch (Exception e) { // TODO: handle exception } } System.out.println(r.name+"..."+r.sex); r.flag = false; r.notify(); } } } } public class Main { public static void main(String[] args) { Resource r = new Resource(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } }
三:等待唤醒机制代码优化
资源中的成员为了可控,应该为私有的,对外提供方法
所以同步的操作,就在Resource类中执行,应用同步函数
class Resource extends Object { private String name; private String sex ; private boolean flag = false; public synchronized void set(String name,String sex) { // TODO Auto-generated constructor stub if(flag) { try { this.wait(); } catch (Exception e) { // TODO: handle exception } } this.name = name; this.sex = sex; flag = true; this.notify(); } public synchronized void out() { if(!flag) { try { this.wait(); } catch (Exception e) { // TODO: handle exception } System.out.println(name+" : "+sex); flag = false; this.notify(); } } } class Input implements Runnable { Resource r; Input(Resource r) { this.r = r; } public void run() { int x = 0; while(true) { if(x==0) { r.set("BLF", "male"); } else { r.set("妮妮妮妮", "female"); } x = (++x)%2; } } } class Output implements Runnable { Resource r; public Output(Resource r) { // TODO Auto-generated constructor stub this.r = r; } public void run() { while(true) { r.out(); } } } public class Main { public static void main(String[] args) { Resource r = new Resource(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } }
JAVA学习第二十六课(多线程(五))- 多线程间的通信问题
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。