等待唤醒机制

       在开始学习等待唤醒机制之前,有必要搞清一个概念——线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制

     等待唤醒机制所涉及到的方法:

  1. wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
  2. notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
  3. notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。

       其实,所谓唤醒的意思就是让 线程池中的线程具备执行资格。必须注意的是,这些方法都是在 同步中才有效。同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。

       仔细查看JavaAPI之后,发现这些方法 并不定义在 Thread中,也没定义在Runnable接口中,却被定义在了Object类中,为什么这些操作线程的方法定义在Object类中?

       因为这些方法在使用时,必须要标明所属的锁,而锁又可以是任意对象。能被任意对象调用的方法一定定义在Object类中。

等待唤醒机制

接下里,先从一个简单的示例入手:

等待唤醒机制

如上图所示,输入线程向Resource中输入name ,sex , 输出线程从资源中输出,先要完成的任务是:

1. 当input发现Resource中没有数据时,开始输入,输入完成后,叫output来输出。如果发现有数据,就wait();

2. 当output发现Resource中没有数据时,就wait() ;当发现有数据时,就输出,然后,叫醒input来输入数据。

 

下面代码,模拟等待唤醒机制的实现:

模拟资源类

public class Resource {

    private String name;

    private String sex;

    private boolean flag = false; //flag作为标记

 

    public synchronized void set(String name, String sex) {

        if (flag)

            try {

                wait();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        // 设置成员变量

        this.name = name;

        this.sex = sex;

        // 设置之后,Resource中有值,将标记该为 true ,

        flag = true;

        // 唤醒output

        this.notify();

    }

 

    public synchronized void out() {

        if (!flag)

            try {

                wait();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        // 输出线程将数据输出

        System.out.println("姓名: " + name + ",性别: " + sex);

        // 改变标记,以便输入线程输入数据

        flag = false;

        // 唤醒input,进行数据输入

        this.notify();

    }

}

 

输入线程任务类

public class Input implements Runnable {

    private Resource r;

 

    public Input(Resource r) {

        this.r = r;

    }

 

    @Override

    public void run() {

        int count = 0;

        while (true) {

            if (count == 0) {

                r.set("小明", "男生");

            } else {

                r.set("小花", "女生");

            }

            // 在两个数据之间进行切换

            count = (count + 1) % 2;

        }

    }

}

 

输出线程任务类

public class Output implements Runnable {

    private Resource r;

 

    public Output(Resource r) {

        this.r = r;

    }

 

    @Override

    public void run() {

        while (true) {

            r.out();

        }

    }

}

 

测试类

public class ResourceDemo {

    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();

    }

}