线程通信之生产者和消费者案例

使用 Object 类的 wait() 和 notify() 方法 (不适用锁机制)

只有同步监听对象才可以调用 wait() 和 notify() 方法,否则报错
线程之间进行通信,且防止耦合度过高,使用一个中间类作为通信的共同资源

  • 需要使用 synchronized 保证一个过程的原子性
  • 使用 isEmpty 变量作为标志参数,在结束生产和结束消费之后改变该值
  • 使用 Object 类的 wait() 方法,判断资源状态,若存在则当前进程进入等待池
  • 使用 Object 类的 notify() 方法,在结束生产和结束消费之后唤醒其他线程
  • 值得注意的是:只有同步监听对象才可以调用 wait() 和 notify() 方法,否则报错

测试类

source 作为两个线程的参数传入

public class TestDemo {
    public static void main(String[] args) {
        ShareSources source = new ShareSources();
        new Producer(source).start();
        new Comsumer(source).start();
    }
}

资源类

public class ShareSources {
    private String name;
    private String sex;
    private Boolean isEmpty = true;//使用一个参数作为标志

    /**
     * 存入数据
     * @param name
     * @param sex
     */
    synchronized public void push(String name, String sex) {//同步方法,保证了该方法的原子性
        try {
            //此处使用While比If更加合理,
            while (!isEmpty) {// 生产者是当前线程,如果资源任存在,则当前线程释放锁,进入等待池中,释放后,消费者进程获得锁
                this.wait();//this 指的是 source 对象 进入等待池中的线程只能被其他线程唤醒,这里只能在消费者线程中唤醒
            }
            //---------------------开始生产-------------------------
            this.name = name;
            Thread.sleep(10);
            this.sex = sex;
            //---------------------结束生产-------------------------
            isEmpty = false;
            this.notifyAll();//同时将其他线程唤醒
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 获取资源
     */
    synchronized public void get() {
        try {
            while (isEmpty) {//如果资源不存在
                this.wait();//当前线程是消费者,进入等待池
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //---------------------开始消费-------------------------
        Thread.sleep(10);       
        System.out.println(this.name + "-" + this.sex);
        //---------------------结束消费-------------------------
        isEmpty = true;
        this.notifyAll();//同时将其他线程唤醒
    }
}

生产者类

生产者可能存在多个,且需要与消费者不同线程

public class Producer extends Thread {
    private ShareSources source = null;

    public Producer(ShareSources source) {//通过构造器获取相同的资源
        this.source = source;
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if (i % 2 == 0) {
                source.push("春哥", "男");
            }else {
                source.push("凤姐", "女");
            }
        }
    }
}

消费者类

public class Comsumer extends Thread {
    private ShareSources source = null;

    public Comsumer(ShareSources source) {
        this.source = source;
    }

    public void run() {
        for (int i = 0; i < 50; i++) {
            source.get();
        }
    }
}

使用 Lock 和 condition 接口

资源类(只有该类发生变化)

需要注意的是,condition 的操作一定要在获取锁之后,释放锁之前执行,否则报错

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ShareSources {
    private String name;
    private String sex;
    private Boolean isEmpty = true;
    // 实例化锁
    private final Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();// 由于Condition是一个接口,lock.newCondition()方法返回一个绑定的Condition实例

    /**
     * 存入数据
     * 
     * @param name
     * @param sex
     */
    public void push(String name, String sex) {
        lock.lock();
        try {
            if (!isEmpty) {
                condition.await();// 使用condition的await()方法相当于 Object 类的 wait 方法
            }
            this.name = name;
            Thread.sleep(10);
            this.sex = sex;
            isEmpty = false;
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取资源
     */
    public void get() {
        lock.lock();
        try {
            if (isEmpty) {
                condition.await();// 使用condition的await()方法相当于 Object 类的 wait 方法
            }
            Thread.sleep(10);
            System.out.println(this.name + "-" + this.sex);
            isEmpty = true;
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

转载于:https://www.cnblogs.com/cenzhongman/p/7307743.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值