一 wait、notify、notifyAll()的基本概念
wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。
- 如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
- 如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
- 如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
其中wait方法有三个over load方法:
wait()
wait(long)
wait(long,int)
wait方法通过参数可以指定等待的时长。如果没有指定参数,默认一直等待直到被通知。
二 代码解析
两个线程一个为Input向资源中写入数据,一个为output从资源中读取数据。当写入线程写入数据的时候,首先要对资源加锁,如果资源中没有数据,则向资源中写入数据,写入完毕后释放锁(notify),如果资源有数据,则等待,直到资源中没有数据为止才继续写入数据。
特别需要注意的的写入线程中标红的部分,else不能加上。因为两个线程都在操作同一个资源,r.isflag()为true判断完毕后,判断完毕后,r.flag可能已经为false。此时会出现与要求不符的情况。
public void
int
while (true) {
synchronized (r) {
if (r.isFlag())//如果已经有数据
{
try
r.wait();//已经阻塞线程了 阻塞之后 肯定为f.flag一定为false
} catch
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{//如果加上else,那么会出现一种情况if判断时为true,判断完毕后,r.flag已经为false。
//会出现数据不一致的情况 因此不需要加else
if
r.setName("lxb");
r.setSex("男");
}else
{
r.setName("张红");
r.setSex("女");
}
x=++x%2;
r.setFlag(true);
r.notify();//通知其他获取对象锁的线程
}
}
}
}
正确的代码如下:
package WN;
public class Input extends Thread {
private Res r;
public Input(Res r) {
this.r = r;
}
@Override
public void run() {
int x = 0;
while (true) {
synchronized (r) {
if (r.isFlag())//如果已经有数据
{
try {
r.wait();//已经阻塞线程了 阻塞之后 肯定为f.flag一定为false
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//如果加上else,那么会出现一种情况if判断时为true,判断完毕后,r.flag已经为false。
//会出现数据不一致的情况 因此不需要加else
if (x % 2 == 0) {
r.setName("刘泽");
r.setSex("男");
}else
{
r.setName("张红");
r.setSex("女");
}
x=++x%2;
r.setFlag(true);
r.notify();//通知其他获取对象锁的线程
}
}
}
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
in.start();
out.start();
}
}
package WN;
public class Res {
private String name;
private String sex;
private boolean flag=false;
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 boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
package WN;
public class Output extends Thread{
private Res r;
public Output (Res r) {
this.r = r;
}
@Override
public void run() {
int x = 0;
while (true) {
synchronized (r) {
if (r.isFlag())//如果已经有数据
{
System.out.println(r.getName()+","+r.getSex());
r.setFlag(false);//已经取出数据
r.notify();
}else//没有数据
{
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}