zoukankan      html  css  js  c++  java
  • 线程通信之生产者和消费者案例

    使用 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();
    		}
    	}
    }
  • 相关阅读:
    Systemd 指令
    2018年书单
    2017年书单
    Centos7 Devstack [Rocky] 重启后无法联网
    kvm虚拟机操作相关命令及虚拟机和镜像密码修改
    负载均衡原理-转
    用配置文件里面的参数值替换yaml模板中的变量值【python】
    linux工具之sar
    利用系统缓存优化程序的运行效率
    Elasticsearch单机部署
  • 原文地址:https://www.cnblogs.com/cenzhongman/p/7307743.html
Copyright © 2011-2022 走看看