package com.liujunhua.ith02;
/**
* 线程的等待唤醒机制
* 两个线程对同一资源进行操作,为保证两者操作资源的独立性,出现了等待唤醒机制。
* 1.Input线程负责对变量赋值,为了避免在Input在具有CPU执行权时,进行重复的变量赋值动作,
* 当首次赋值后进行标记,当线程再次赋值的时候,先对标记进行判断,若已经赋值并且该数值还没有
* 被Output输出,Input线程就等待。即放弃执行权。
* 2.当Input等待的时候Output就会获得CPU执行权,就会执行相应的输出操作。当完成输出操作后,它将标记为已经操作状态。
* 当下次执行的时候,如果发现标记已经输出,并且Input没有进行新的赋值,那么就会进入等待状态。
*
* 从而实现了等待唤醒机制。
*
* wait();
* notify();
* notifyAll();
*
* 这些方法都使用在同步中,因为要对持有监视器(锁)的线程进行操作。
* 所以要使用在同步中,因为只有同步才具有锁。
*
* 但是为什么这些操作线程的方法要定义在Object类中呢?
*
* 那是因为这些方法在操作同步中的线程是,都必须要标识他们所操作线程的锁,
* 只有同一个锁上的被等待的线程,可以被同一个锁上的notify唤醒。
*
* 也就是说,等待和唤醒必须是同一个锁。
*
* 而锁可以是任意对象,所以可以被任意对象调用的方法定义在object类中。
*/
public class Demo01 {
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();
}
}
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;
}
public void print(){
System.out.println(this.name+"........"+this.sex);
}
}
/**
* 这里线程锁的创建很有技巧性,如果仅仅是简单的obj对象,肯定是不行的,因为一个obj不可能在两个类里面都可以用。
* 但此时又需要两个同步代码块用同一个线程锁,这里便采用了两个线程共同操作的Res对象作为线程锁,很好的解决了线程的安全问题。
*/
class Input implements Runnable {
private Res r;
Input(Res r) {
this.r = r;
}
@Override
public void run() {
// TODO Auto-generated method stub
int mark = 0;
while (true) {
synchronized (r) {
if(r.isFlag())
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (mark == 0) {
r.setName("mike");
r.setSex("man");
} else {
r.setName("丽丽");
r.setSex("女女");
}
mark = (mark + 1) % 2;
r.setFlag(true);
r.notify();
}
}
}
}
class Output implements Runnable {
private Res r;
Output(Res r) {
this.r = r;
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
synchronized (r) {
if(!r.isFlag()){
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
r.print();
r.setFlag(false);
r.notify();
}
}
}
}