【Java面试之操作系统】

线程之间的通信,要掌握生产者-消费者模型

持续更新记录学习

多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间的一个变量的使用或者操作。
就是多个线程在操作同一份数据时,避免对同一共享变量的争夺。
于是,引入了等待唤醒机制:

wait()、notify()

要确保调用wait()方法的时候拥有锁,所以wait()方法必须放在synchronized方法或者synchronized代码块中

实现线程通信例子

生产者-消费者模型

面包类(包含生产方法和消费方法)

package thredmessage;

/**
 * 面包类
 * 
 * @author zhou-di-an
 *
 *         2019年10月31日
 */
public class Breads {
	// 面包类的id
	private int bid;

	// 面包的个数
	private int num;

	// 生产面包的方法
	public synchronized void product() {

		// 当面包的数量不为0时,该方法处于等待状态
		if (0 != num) {
			try {
				wait();// 等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		// 当面包数量为0时,那么就开始生产面包
		num++; // 数量加1

		bid++; // id加1

		String threadname = Thread.currentThread().getName();
		System.out.println(threadname + "生产了一个编号为" + bid + "的面包!");
		notify(); // 当执行完后,去唤醒其他处于等待的线程
	}

	// 消费面包的方法
	public synchronized void consume() {
		// 当面包数量为0时,该方法处于等待状态
		if (num == 0) {
			try {
				wait(); // 等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		// 消费完面包了,所有面包的数量降为0
		num--; // 数量减1

		String namea1 = Thread.currentThread().getName();
		System.out.println(namea1 + "买了一个编号为" + bid + "的面包");
		notify(); // 当执行完后,去唤醒其他处于等待的线程
	}

	// get和set
	public int getBid() {
		return bid;
	}

	public void setBid(int bid) {
		this.bid = bid;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

	// 构造
	public Breads(int bid, int num) {
		super();
		this.bid = bid;
		this.num = num;
	}

	public Breads() {
		super();
	}

}

生产面包的类

package thredmessage;

/**
 * 线程通信--生产类
 * 
 * @author zhou-di-an
 *
 *         2019年10月31日
 */
public class Producer extends Thread {
	// 获得面包的类
	private Breads breads;

	// 无参构造
	public Producer() {
		super();
	}

	// 有参构造
	public Producer(Breads breads) {
		super();
		this.breads = breads;
	}

	public Breads getBreads() {
		return breads;
	}

	public void setBreads(Breads breads) {
		this.breads = breads;
	}

	@Override
	public void run() {
		pro();
	}

	// 生产面包
	private void pro() {
		// 20个
		for (int i = 0; i < 10; i++) {
			try {
				// 为了明显看到效果,睡0.3秒
				Thread.currentThread().sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// 调用面包类的生产面包的方法
			breads.product();
		}
	}
}

消费面包的类

package thredmessage;

/**
 * 线程通信--消费者类
 * 
 * @author zhou-di-an
 *
 *         2019年10月31日
 */
public class Consume extends Thread {
	// 获得面包的类
	private Breads breads;

	public Breads getBreads() {
		return breads;
	}

	public void setBreads(Breads breads) {
		this.breads = breads;
	}

	public Consume(Breads breads) {
		super();
		this.breads = breads;
	}

	public Consume() {

	}

	@Override
	public void run() {
		con();
	}

	public void con() {
		// 与生产者保持一致
		for (int i = 0; i < 10; i++) {
			try {
				Thread.currentThread().sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// 消费面包
			breads.consume();
		}
	}
}

测试类

package thredmessage;

/**
 * 线程通信--测试类
 * 
 * @author zhou-di-an
 *
 *         2019年10月31日
 */
public class Test {
	public static void main(String[] args) {
		// new一个面包类
		Breads breads = new Breads();

		// new一个生产者类
		Producer producer = new Producer(breads);

		// new一个消费者类
		Consume consume = new Consume(breads);

		// new一个包含消费者的线程
		Thread t1 = new Thread(producer, "生产者");

		// new一个包含生产者类的线程
		Thread t2 = new Thread(consume, "消费者");

		// 启动线程
		t1.start();
		t2.start();
	}
}

测试结果

生产者生产了一个编号为1的面包!
消费者买了一个编号为1的面包
生产者生产了一个编号为2的面包!
消费者买了一个编号为2的面包
生产者生产了一个编号为3的面包!
消费者买了一个编号为3的面包
生产者生产了一个编号为4的面包!
消费者买了一个编号为4的面包
生产者生产了一个编号为5的面包!
消费者买了一个编号为5的面包
生产者生产了一个编号为6的面包!
消费者买了一个编号为6的面包
生产者生产了一个编号为7的面包!
消费者买了一个编号为7的面包
生产者生产了一个编号为8的面包!
消费者买了一个编号为8的面包
生产者生产了一个编号为9的面包!
消费者买了一个编号为9的面包
生产者生产了一个编号为10的面包!
消费者买了一个编号为10的面包

你可能感兴趣的:(面试,操作系统)