Java多线程-3(3)

8 线程协作(以生产者消费者模型举例)

8.1 生产者消费者模型问题

  1. 仓库只能存放一件产品,生产者将生产的产品放入仓库,消费者从仓库中产品消费取走
  2. 若仓库中无产品,生产者将产品存入仓库,否则停止生产并等待至被消费者取走
  3. 若仓库有产品,消费者消费取走产品,否则停止消费并等待生产者放入产品

producer -> 数据缓冲区 -> consumer

注:synchronized可组织并发更新访问同一共享资源以实现同步,但不能用来实现不同线程之间的消息传递。

8.2 解决方案

image

注:均为Object类的final方法,只能在同步方法或同步代码块中使用,否则会抛出IllegalMonitorStateException异常

8.3 解决方法示例(管程法)

点击查看代码
public class GuanCheng {
	public static void main(String[] args) {
		Buffer buffer = new Buffer();
		Producer Jing = new Producer(buffer);
		Consumer Kai = new Consumer(buffer);

		new Thread(Jing).start();
		new Thread(Kai).start();

	}
}

class Chicken {
	private int id;

	public Chicken(int id){
		this.id = id;
	}

	public int getId(){
		return this.id;
	}
}

class Producer implements Runnable{
	private Buffer buffer;

	public Producer(Buffer buffer){
		this.buffer = buffer;
	}

	@Override
	public void run() {
		for (int i = 1; i <= 100; i++) {
			buffer.store(new Chicken(i));
		}

	}
}

class Consumer implements Runnable{
	private Buffer buffer;
	public Consumer(Buffer buffer){
		this.buffer = buffer;
	}

	@Override
	public void run() {
		for (int i = 1; i <= 100; i++) {
		buffer.sell();
		}

	}
}

class Buffer{
	private final int MAX = 10;
	private Queue<Chicken> queue = new LinkedList<>();
	public synchronized void store(Chicken chicken){
		//若已有十只鸡,则停止生产并通知消费者消费;否则继续生产
		if(queue.size() >= MAX){
			try{
				this.wait();
			} catch (InterruptedException e){
				System.out.println("仓库鸡满了!");
			}
		}
		queue.offer(chicken);
		System.out.println("生产了第" + chicken.getId() + "只鸡" + ", 仓库余量为" + queue.size());
		this.notify();
	}

	public synchronized void sell() {
		//若没有鸡,则通知生产者进行生产;否则消费鸡
		if(queue.size() == 0){
			try{
				this.wait();
			} catch (InterruptedException e){
				System.out.println("没有鸡可吃了!");
			}
		}
		System.out.println("消费了第" + queue.poll().getId() +"只鸡");
		this.notify();
	}
}

9 线程池

9.1 线程池概述

产生背景:线程经常创建和销毁、使用量特别大的资源(并发情况下的线程),对性能影响较大

思路:提前创建线程放入线程池中,使用时直接获取,使用完放回池中。(避免频繁创建销毁线程,实现线程重复利用)

优点:

  1. 提高响应速度(减少创建新线程时间)
  2. 降低资源消耗(重复利用线程池中线程,不需每次都创建)
  3. 便于线程管理
    1. corePoolSize:核心池大小
    2. 最大线程数
    3. 线程没有任务时最多保持多长时间后终止

9.2 使用线程池

  1. JDK 5.0提供了线程池相关API:ExecutorSService和Executors
  2. ExecutorService:真正的线程池接口(ThreadPoolExecutor为其常见子实现类)
    1. void execute(Runnable command):执行任务/命令,无返回值,一般用来执行Runnable
    2. <T>Future<T> submit(Callable<T> task): 执行任务,有返回值。一般用来执行Callable
    3. void shutdown():关闭线程池
      ...
  3. Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

9.3 使用示例

public class TestPool {
	public static void main(String[] args) {
		//1.创建服务,线程池
		ExecutorService service = Executors.newFixedThreadPool(10);

		//2.执行
		service.execute(new MyThread());
		service.execute(new MyThread());
		service.execute(new MyThread());
		service.execute(new MyThread());

		//3.关闭连接
		service.shutdown();
	}
}
posted @ 2021-09-21 17:10  rttrti  阅读(36)  评论(0编辑  收藏  举报