线程通讯

来源:互联网 发布:eva625软件下载 编辑:程序博客网 时间:2024/06/04 18:39

线程通讯:其实就是多个线程在操作同一个资源,但是操作的动作不同。


解决安全问题


class Res{String name;String sex;}class Input implements Runnable{private Res r;Input(Res r){this.r = r;}public void run(){int x = 0;while(true){if(x == 0){r.name = "mike";r.sex = "man";}else{r.name = "丽丽";r.sex = "女";}x = (x + 1)%2;}}}class Output implements Runnable{private Res r;Output(Res r){this.r = r;}public void run(){while(true){System.out.println(r.name+"..."+r.sex);}}}class InputOutputDemo{public static void main(String[] args){Res r = new Res();Input in = new Input(r);Output out = new Output(r);Thread t1 = new Thread(in);Thread t2 = new Thread(out);t1.start();t2.start();}}

运行结果会出现这种情况:

这是因为:假如原先输入中的姓名、性别分别是丽丽、女。再一次输入的时候,只添入了姓名“mike”,还没添入性别的时候,执行权被输出线程抢走,输出“mike...女”的情况。

同步来解决:

class Res{String name;String sex;}class Input implements Runnable{private Res r;Object obj = new Object();Input(<span style="color:#333333;">Res r</span>){this.r = r;}public void run(){int x = 0;while(true){synchronized(<span style="color:#cc33cc;">obj</span>){if(x == 0){r.name = "mike";r.sex = "man";}else{r.name = "丽丽";r.sex = "女";}x = (x + 1)%2;}}}}class Output implements Runnable{private Res r;Object obj = new Object();Output(Res r){this.r = r;}public void run(){while(true){synchronized(<span style="color:#cc33cc;">obj</span>){System.out.println(r.name+"..."+r.sex);}}}}class InputOutputDemo{public static void main(String[] args){Res r = new Res();Input in = new Input(r);Output out = new Output(r);Thread t1 = new Thread(in);Thread t2 = new Thread(out);t1.start();t2.start();}}

输出结果:

加了锁之后仍然出现问题,要看看是否满足那两个准则。

1.是否是两个或多个线程。

2.是否是同一个锁。

 

显然第一个条件满足。但是第二个条件不满足。因为Object类创建的是两个对象。

解决方法:可以用 类名:class,内存中有四个唯一的类,所以锁可以是Res.class,Input.class,Output.clss,InputOutputDemo.class。因为资源r也是唯一的,所以锁也可以是r


等待唤醒机制

 

还是上一个程序,它的打印结果是“mike...man”成片出现,“丽丽...女”成片出现。这种情况的原因是输入线程抢到执行权后,它会不止一次的输入,不断更新当前的输入结果。而当输出线程抢到CPU执行权后,它也会不止一次的输出,于是就出现了上述情形。 

我们要的结果应该是输入一次,紧接着输出一次。这就用到了等待唤醒机制。


<pre name="code" class="java">class Res{String name;String sex;boolean flag = false;public <span style="color:#66ffff;">synchronized</span> void set(String name,String sex){if(flag)try{<span style="color:#ff0000;">this.wait()</span>;}catch(Exception e){}this.name = name;this.sex = sex;flag = true;<span style="color:#ff0000;">this.notify()</span>;}public <span style="color:#66ffff;">synchronized</span> void out(){if(!flag)try{<span style="color:#33cc00;">this.wait()</span>;}catch(Exception e){}System.out.println(r.name+"..."+r.sex);flag = false;<span style="color:#33cc00;">this.notify();</span>}}class Input implements Runnable{private Res r;Input(Res r){this.r = r;}public void run(){int x = 0;while(true){if(x == 0){r.set("mike","man");}else{r.set("丽丽","女");}x = (x + 1)%2;}}}}class Output implements Runnable{private Res r;Output(Res r){this.r = r;}public void run(){while(true){r.out();}}}class InputOutputDemo{public static void main(String[] args){Res r = new Res();Input in = new Input(r);Output out = new Output(r);Thread t1 = new Thread(in);Thread t2 = new Thread(out);t1.start();t2.start();}}



wait(),notify(),notifyAll()  都使用在同步中,因为要对持有监视器(锁)的线程操作。

所以要使用在同步中,因为只要同步中才具有锁。

 

为什么这些操作线程的方法要定义在Object类中呢?

 

因为这些方法在操作同步线程时,都必须要标识它们所操作线程持有的锁,

只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒,不可以被不同锁上的线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。

 

而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。

0 0
原创粉丝点击