--------------------ASP.Net+Android+IOS开发、.Net培训、期待与您交流! --------------------
1. 线程间通信
1. 概述
线程间通信:就是不同的线程共享同一资源,然后对资源进行不同的操作行为,说白了,在执行的线程运行代码是不一样的,但是代码中还含有共享资源。
2. 举例说明
例如:例如就是有一资源(Res 煤),有两个线程分别执行的是赋值和取出(两辆卡车,一个是运来,一个是运走)
/*共享的资源*/ public class Res { private String name; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public StringgetSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } /*输入类*/ public class Input implements Runnable { private Res r = null;// 定义了一个资源 public Input(Res r) {// 通过构造方法初始化 this.r = r; } public void run() { int x = 0; while (true) { if (x == 0) { this.r.setName("张三"); this.r.setSex("男"); } else { this.r.setName("Joney"); this.r.setSex("female"); } x = (x + 1) % 2; } } } /*输出类*/ public class Output implements Runnable { private Res re = null; public Output(Res r) {//初始化资源 this.re = r; } public void run() { while (true) { System.out.println(this.re.getName() + ":" + this.re.getSex()); } } } /*测试类*/ public class Text { public static void main(String[] agrs) { Res r = new Res(); Input in = new Input(r); Output out = new Output(r); new Thread(in).start(); new Thread(out).start(); } } 从结果中可以看出,结果和我们预测的结果不一样,会出现这样的结果: Joney:男 张三:female Joney:female 张三:男 张三:female
3. 优化通信
优化,刚才的通信,就是加上同步锁,在加锁之前,一定要明确,必须是两个或者是多个线程,锁的对象必须是同一个锁
/*输入类*/ public class Input implements Runnable { private Res r = null;// 定义了一个资源 public Input(Res r) {// 通过构造方法初始化 this.r = r; } public void run() { int x = 0; while (true) { synchronized (r) {//加锁,对象指定的是共享资源 if (x == 0) { this.r.setName("张三"); this.r.setSex("男"); } else { this.r.setName("Joney"); this.r.setSex("female"); } } x = (x + 1) % 2; } } } /*输出类*/ public class Output implements Runnable { private Res re = null; public Output(Res r) {//初始化资源 this.re = r; } public void run() { while (true) { synchronized (re) {//加锁,对象指定的是共享资源 System.out.println(this.re.getName() + ":" + this.re.getSex()); } } } }
这样结果就是相匹配了,这样我们一定要灵活运用同步,并且记住同步需要的条件。
2. 等待唤醒机制
1. 概述和机制
利用wait(),notify()和notifyAll()三个方法。
wait()方法是线程放弃的执行资格,notify()唤醒监视器上等待的线程,默认的是从第一个开始。notifyAll()唤醒的是监视器(锁)上所有等待的线程。为什么这三个函数都是在Object类中,因为监视器(锁)对象是任何对象,要用对象来是线程等待和唤醒,那么就得放在Object类中,才能调用任何对象的方法。
在共享资源资源上,定义了一个可以标识资源状态 的标识位,在监视器判断标志位,若不符合执行条件则是线程等待,用此时监视器对象来使线程等待,否则继续执行,到最后改变标志位,然后唤醒的等待的线程(是另外一个共享资源的线程),同样另外一个线程(或者是多个)会执行同样的操作。
只有同一个锁上的被等待的线程,可以被同一个锁上的notify()唤醒,不能对不同锁上的线程进行唤醒,就是等待和唤醒必须是同一个锁。
2. 举例
/*共享的资源*/ public class Res { private String name; private String sex; private boolean flag = false;//标志位,用来表示资源的状态 public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } /*输入类*/ public class Input implements Runnable { private Res r = null;// 定义了一个资源 public Input(Res r) {// 通过构造方法初始化 this.r = r; } public void run() { int x = 0; while (true) { synchronized (r) {// 加锁,对象指定的是共享资源 if (r.isFlag())// flag=true表示此时里面有资源,或者是资源没有被读取呢,不能继续添加 try { r.wait(); } catch (InterruptedException e) { e.printStackTrace(); } if (x == 0) { this.r.setName("张三"); this.r.setSex("男"); } else { this.r.setName("Joney"); this.r.setSex("female"); } x = (x + 1) % 2; r.setFlag(true);// 标识此时已经赋值了,不能在连续赋值了 r.notify(); } } } } /*输出类*/ public class Output implements Runnable { private Res r = null; public Output(Res r) {// 初始化资源 this.r = r; } public void run() { while (true) { synchronized (r) { if (!r.isFlag())// flag=false,标识此时没有资源,或者资源已经被读取了 try { r.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.r.getName() + ":" + this.r.getSex()); r.setFlag(false);// 读取资源后,然后把标志为false,标识此时已经被读取出来了,不能在读取了 r.notify(); } } } } /*测试类*/ public class Text { public static void main(String[] agrs) { Res r = new Res(); Input in = new Input(r); Output out = new Output(r); new Thread(in).start(); new Thread(out).start(); } } 结果: 张三:男 Joney:female 张三:男 Joney:female 张三:男 Joney:female 张三:男 Joney:female 张三:男
3.优化例子
在共享资源中使用同步方法老设置名称和取值
/*共享的资源*/ public class Res { private String name; private String sex; private boolean flag = false;// 标志位,用来表示资源的状态 /*同步函数赋值对象是 this*/ public synchronized void set(String name, String sex) {// 使用同步函数 if (flag) try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } this.name = name;//赋值 this.sex = sex; this.flag = true;//改变标识位 this.notify();//唤醒等待线程 } /*同步函数读取 对象是this*/ public synchronized void show() {// 同步函数 if (!flag) try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.name + ":" + this.sex);//读取 this.flag = false;//改变标识位 this.notify();//唤醒等待线程 } } /*输入类*/ public class Input implements Runnable { private Res r = null;// 定义了一个资源 public Input(Res r) {// 通过构造方法初始化 this.r = r; } public void run() { int x = 0; while (true) { if (x == 0) { r.set("张三", "男"); } else { r.set("Joney", "female"); } x = (x + 1) % 2; } } } /*输出类*/ public class Output implements Runnable { private Res r = null; public Output(Res r) {// 初始化资源 this.r = r; } public void run() { while (true) { r.show(); } } } /*测试类*/ public class Text { public static void main(String[] agrs) { Res r = new Res(); new Thread(new Input(r)).start(); new Thread(new Output(r)).start(); } }
--------------------ASP.Net+Android+IOS开发、.Net培训、期待与您交流! --------------------