博客信息

多线程间通信(引言、等待唤醒机制)

发布时间:『 2019-05-29 22:38』  博客类别:java基础  阅读(759)

引言

资源存入与取出的并发问题


小李飞刀_线程

将图用代码进行无并发描述

package com.javaxl.thread;

/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2019-05-29 21:34
 * <p>
 * 操作同一个资源
 * 资源中只有姓名和性别
 * 生产者对应一个生产的线程
 * 消费者对应一个消费的线程
 */
public class Demo4 {
    public static void main(String[] args) {
//        一个资源池
        Res r = new Res();
        Thread in = new Thread(new Input(r));
        Thread out = new Thread(new Output(r));
        in.start();
        out.start();

    }
}

class Res {
    String name;
    String sex;
    boolean flag = true;

    public Res(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    public Res() {
    }
}

/**
 * 往资源池中生产
 */
class Input implements Runnable {
    private Res r;
    private int num = 0;

    public Input(Res r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (r) {
                if (num % 2 == 0) {
                    r.name = "tingting";
                    r.sex = "nv";
                } else {
                    r.name = "旺旺";
                    r.sex = "男";
                }
                num++;
            }
        }
    }
}

/**
 * 从资源池消费
 */
class Output implements Runnable {
    private Res r;

    public Output(Res r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (r) {
                System.out.println(r.name + "--------------" + r.sex);
            }
        }
    }
}

控制台结果

小李飞刀_线程

 

加上同步锁出现的问题

小李飞刀_线程

上面代码保证了资源获取的一致性。


等待唤醒机制

现有问题:

需求是往资源池中放入一个资源,然后再从资源池中取一个资源;

但是现在情况是,存入N个资源,在不定数量的取N个资源;

并且注意一点:目前向资源池中存放资源的只有一个线程,从资源池中消费资源的也只有一个线程。

 

 

Wait()

Notify()

notifyAll()

 

都是用在同步中,因为要对持有监听器(锁)的线程操作;

所以要使用在同步中,因为只有同步才具有锁;

 

为什么这些操作线程的方法要定义在Object类中呢?

因为这些方法在操作同步中线程时,都必须要标识他们所操作线程持有的锁;

只有同一个锁上的被等待线程,可以被同一个锁上notify()唤醒;

不可以对不同锁中的线程进行唤醒;

 

也就是说,等待和唤醒必须是同一把锁;

 

而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中;


改进前面生产者消费者产生的问题

package com.javaxl.thread;

/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2019-05-29 21:34
 * <p>
 * 操作同一个资源
 * 资源中只有姓名和性别
 * 生产者对应一个生产的线程
 * 消费者对应一个消费的线程
 */
public class Demo4 {
    public static void main(String[] args) {
//        一个资源池
        Res r = new Res();
        Thread in = new Thread(new Input(r));
        Thread out = new Thread(new Output(r));
        in.start();
        out.start();

    }
}

class Res {
    String name;
    String sex;
    boolean flag = false;

    public Res(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    public Res() {
    }
}

/**
 * 往资源池中生产
 */
class Input implements Runnable {
    private Res r;
    private int num = 0;

    public Input(Res r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (r) {
                if (r.flag){
                    try {
                        r.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                if (num % 2 == 0) {
                    r.name = "tingting";
                    r.sex = "nv";
                } else {
                    r.name = "旺旺";
                    r.sex = "男";
                }
                num++;
                r.flag = true;
                r.notify();
            }
        }
    }
}

/**
 * 从资源池消费
 */
class Output implements Runnable {
    private Res r;

    public Output(Res r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (r) {
                if(!r.flag){
                    try {
                        r.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(r.name + "--------------" + r.sex);
                r.flag = false;
                r.notify();
            }
        }
    }
}

上面代码保证了,在只有一个生产者、一个消费者的情况下,资源池的资源呈现出反复一进一出的现象;

 

 

代码优化(成员私有化)

package com.javaxl.thread;

/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2019-05-29 21:34
 * <p>
 * 操作同一个资源
 * 资源中只有姓名和性别
 * 生产者对应一个生产的线程
 * 消费者对应一个消费的线程
 */
public class Demo4 {
    public static void main(String[] args) {
//        一个资源池
        Res r = new Res();
        Thread in = new Thread(new Input(r));
        Thread out = new Thread(new Output(r));
        in.start();
        out.start();

//        Thread in2 = new Thread(new Input(r));
//        Thread out2 = new Thread(new Output(r));
//        in2.start();
//        out2.start();
    }
}

class Res {
    private String name;
    private String sex;
    private boolean flag = false;
    private int num = 0;

    public Res(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    public Res() {
    }

    /**
     * 往资源池中添加资源
     */
    public synchronized void add(){
        if (this.flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        if (num % 2 == 0) {
            this.name = "tingting";
            this.sex = "nv";
        } else {
            this.name = "旺旺";
            this.sex = "男";
        }
        num++;
        this.flag = true;
        this.notify();
    }

    /**
     * 使用资源池中的资源
     */
    public synchronized void use(){
        if(!this.flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(this.name + "--------------" + this.sex);
        this.flag = false;
        this.notify();
    }

}

/**
 * 往资源池中生产
 */
class Input implements Runnable {
    private Res r;


    public Input(Res r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true) {
             r.add();
          
        }
    }
}

/**
 * 从资源池消费
 */
class Output implements Runnable {
    private Res r;

    public Output(Res r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true) {
             r.use();
        
        }
    }
}




关键字:     Java基础       多线程通信  

备案号:湘ICP备19000029号

Copyright © 2018-2019 javaxl晓码阁 版权所有