Fork me on GitHub

Java 之多线程通信(等待/唤醒)

多线程间通信: 多个线程在处理同一个资源, 但是任务却不同.

等待/唤醒机制

  1. 涉及的方法
    • wait(): 让线程处于冻结状态, 被 wait() 的线程会被存储到线程池中
    • notify(): 唤醒线程池中的任意一个线程
    • notifyAll(): 唤醒线程池中所有的线程
  2. 这些方法必须定义在同步中, 因为这些方法是用于操作线程状态的方法, 必须要明确到底
    操作的是哪个锁上的线程.
  3. 为什么操作线程的方法 wait(), notify(), notifyAll() 定义在了 Object 类中?
    因为这些方法是监视方法, 监视器其实就是锁. 而锁可以是任意的对象, 任意对象都能调用的方法一定
    定义在 Object 类中.

// 资源
class Resource
{
    String name;
    String sex;
    boolean flag = false;
}

// 输入线程
class Input implements Runnable
{
    Resource r;

    // 带参数的构造函数, 以确保输入和输出操作的是同一个资源
    Input(Resource r)
    {
        this.r = r;
    }

    public void run()
    {
        int x = 0;
        while(true)
        {
            synchronized(r)
            {
                if(r.flag)
                    //该异常只能捕获, 不能抛出, 因为父类 Runnable 中 run() 方法没有异常
                    try{r.wait();}catch(InterruptedException e){}
                if(x==0)
                {
                    r.name = "mike";
                    r.sex = "nan";
                }
                else
                {
                    r.name = "丽丽";
                    r.sex = "girlgirlgirl";
                }
                r.flag = true;
                r.notify();
            }
            x = (x+1)%2; // 改变 x 的值, 获得不同的输入值
        }
    }
}

class Output implements Runnable
{
    Resource r;

    // 带参数的构造函数, 确保输入和输出线程操作的是同一个资源
    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 = flase;
                r.notify();
            }
        }
    }
}

class ResourceDemo
{
    public static void main(String[] args)
    {
        // 创建资源
        Resource r = new Resource();

        // 创建任务
        Input in = new Input(r); // 使用带参数的构造函数初始化, 确保操作的为同一个资源 r
        Output out = new Output(r); //使用带参数的构造函数初始化, 确保操作的为同一个资源 r

        // 创建线程
        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);
        // 开启线程
        t1.start();
        t2.start();

    }
}

<--------------------分隔线--------------------------------->
// 将属性私有化, 升级版
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(); // 这时候的锁是 this
    }

    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
{
    Resource r;

    Input(Resource r)
    {
        this.r = r;
    }

    public void run()
    {
        int x = 0;
        while(true)
        {
            if(x==0)
            {
                r.set("mike","nan");
            }
            else
            {
                r.set("lili","nvnv");
            }
            x = (x+1)%2;
        }
    }
}

class Output implements Runnable
{
    Resource r;
    Output(Resource r)
    {
        this.r = r;
    }

    public void run()
    {
        while(true)
        {
            r.out();
        }
    }
}


posted @ 2017-08-31 09:54  小a的软件思考  阅读(238)  评论(0编辑  收藏  举报