java-多线程的练习----妖,等待唤醒,代码重构,lock到condition
1 需求
资源有姓名和性别。
两个线程,
一个负责给姓名和性别赋值,
一个负责获取姓名和性别的值。
要求1,运行一下,解决程序的 "妖"的问题。
要求2,实现正确数据的间隔输出 如
张飞--男
rose--女女女
张飞--男
rose--女女女
要求3,对代码进行重构。
将name,sex私有化,资源类提供对其访问的方法。
要求4,将程序改成JDK1.5的Lock Condition接口。
-------------------------------------
2 妖的出现和解决
原代码:
//描述资源。 class Resource { String name; String sex; } //赋值线程任务 class Input implements Runnable { private Resource r; // private Object obj = new Object(); Input(Resource r)//任务一初始化就必须有要处理的资源。 { this.r = r; } public void run() { int x = 0; while(true) { { if(x==0) { r.name = "张飞"; r.sex = "男"; } else { r.name = "rose"; r.sex = "女女女女"; } } x = (x+1)%2;//实现切换。 } } } //获取值线程任务 class Output implements Runnable { private Resource r ; // private Object obj = new Object(); Output(Resource r) { this.r = r; } public void run() { while(true) { System.out.println(r.name+"....."+r.sex); } } } class ThreadTest2 { 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(); } }
测试结果: 会出现张飞.....女.或者是rose.....男,
分析原因:假如某个时刻,name=rose,sex=女,进入if中,进行了name=张三后就停止了,不进行了sex的赋值,进入打印,这是时的name=张三,sex=女;
解决方法:出现了安全问题.需要加入同步.详情请点击,
//描述资源。
class Resource
{
String name;
String sex;
}
//赋值线程任务
class Input implements Runnable
{
private Resource r;
// private Object obj = new Object();
Input(Resource r)//任务一初始化就必须有要处理的资源。
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
synchronized(r) //加入同步
{
if(x==0)
{
r.name = "张飞";
r.sex = "男";
}
else
{
r.name = "rose";
r.sex = "女女女女";
}
}
x = (x+1)%2;//实现切换。
}
}
}
//获取值线程任务
class Output implements Runnable
{
private Resource r ;
// private Object obj = new Object();
Output(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
synchronized(r) //加入同步
{
System.out.println(r.name+"....."+r.sex);
}
}
}
}
class ThreadTest2
{
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();
}
}
测试结果
-------------------------------------
3 等待唤醒
出现问题:由上面的结果可知,出现了大量的男或女,没有出现一男一女
解决问题:加入等待唤醒.输入后等待,唤醒输出,输出后,唤醒输入;一般要加入个标志
//描述资源。 class Resource { String name; String sex; //定义标记, boolean flag = false; } //赋值线程任务 class Input implements Runnable { private Resource r; // private Object obj = new Object(); Input(Resource r)//任务一初始化就必须有要处理的资源。 { this.r = r; } public void run() { int x = 0; while(true) { synchronized(r) { if(r.flag) try{r.wait();}catch(InterruptedException e){}//等待唤醒机制 if(x==0) { r.name = "张飞"; r.sex = "男"; } else { r.name = "rose"; r.sex = "女女女女"; } r.flag = true; r.notify(); //等待唤醒机制 } x = (x+1)%2;//实现切换。 } } } //获取值线程任务 class Output implements Runnable { private Resource r ; // private Object obj = new Object(); Output(Resource r) { this.r = r; } public void run() { while(true) { synchronized(r) { if(!r.flag)//等待唤醒机制 try{r.wait();}catch(InterruptedException e){} System.out.println(r.name+"....."+r.sex); r.flag = false; r.notify();//等待唤醒机制 } } } } class ThreadTest2_2 { 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(); } }
测试结果
-------------------------------------
4 代码重构
解决问题:将name,sex私有化,资源类提供对其访问的方法。这时加同步要放在共有资源里面
//描述资源。 class Resource { private String name; // private String sex; //代码重构 //定义标记, private boolean flag = false; //赋值功能。 public synchronized void set(String name,String sex)// //代码重构 { if(flag) try{this.wait();}catch(InterruptedException e){} this.name = name; this.sex = sex; flag = true; this.notify(); } //获取值。 public synchronized void out() { if(!flag) try{this.wait();}catch(InterruptedException e){} System.out.println(name+"------"+sex); flag = false; this.notify(); } } //赋值线程任务 class Input implements Runnable { private Resource r; Input(Resource r)//任务一初始化就必须有要处理的资源。 { this.r = r; } public void run() { int x = 0; while(true) { if(x==0) { r.set("张飞","男"); } else { r.set("rose","女女女女"); } x = (x+1)%2;//实现切换。 } } } //获取值线程任务 class Output implements Runnable { private Resource r ; Output(Resource r) { this.r = r; } public void run() { while(true) { r.out(); } } } class ThreadTest2_3 { 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(); } }
-------------------------------------
5,将程序改成JDK1.5的Lock Condition接口
解决问题:Lock替换了 同步函数或者同步代码块。Condition替代了 监视器方法,将监视器方法从锁上分离出来,单独封装成Condition对象。
import java.util.concurrent.locks.*; //描述资源。 class Resource { private String name; private String sex; //程序改成JDK1.5的Lock Condition接口 //定义标记, private boolean flag = false; //先创建锁对象。 private final Lock lock = new ReentrantLock();// //通过锁对象获取监视器对象。 private Condition con = lock.newCondition();// //赋值功能。 public void set(String name,String sex) { lock.lock();// try{ if(flag) try{con.await();}catch(InterruptedException e){}// this.name = name; this.sex = sex; flag = true; con.signal();// }finally{ lock.unlock();// } } //获取值。 public void out() { lock.lock();// try{ if(!flag) try{con.await();}catch(InterruptedException e){}// System.out.println(name+"------"+sex); flag = false; con.signal();// }finally{ lock.unlock();// } } } //赋值线程任务 class Input implements Runnable { private Resource r; Input(Resource r)//任务一初始化就必须有要处理的资源。 { this.r = r; } public void run() { int x = 0; while(true) { if(x==0) { r.set("张飞","男"); } else { r.set("rose","女女女女"); } x = (x+1)%2;//实现切换。 } } } //获取值线程任务 class Output implements Runnable { private Resource r ; Output(Resource r) { this.r = r; } public void run() { while(true) { r.out(); } } } class ThreadTest2_4 { 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(); } }
作者:8亩田
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.
本文如对您有帮助,还请多帮 【推荐】 下此文。
如果喜欢我的文章,请关注我的公众号
如果有疑问,请下面留言