多线程work thread模式+线程池demo模拟

设想在工厂里 有一个管道 客人将请求放到管道里 传递员工

工作人员读取请求单 然后去工作 没请求时候就等着
客人看不到工厂内部构造 他只看到了管道 什么都不知道
在客户端没有 工作人员这个类 客户端看不到 只能看到管道
说明管道帮助创建和启动了工作人员类 这很像threadpool

角色

在这里插入图片描述
在这里插入图片描述

channle类

还是所有的模式 都一定会有一个目标类 即操作对象 本模式是channle类 就像场景介绍一样 里面维护了创建启动工作人员类的功能 还有放请求的数组

  • 由于放/取对象时需要判断条件 多线程的if 就是While 此处还要记得守护模式 就是wait notify 通信机制
request类

一个数据 维护属性 名字 编号 还有方法

clientThread类

线程类 维护的run中的业务是 调用操作类channle的放对象方法 循环创造请求 否则常见了几个线程类 就创建了几个请求

workthread类

线程类 维护的run中的业务是 调用操作类的channle的取对象方法 循环取对象 否则初始了几个线程类 就取走几个请求

优点

在这里插入图片描述
在这里插入图片描述

  1. 提前初始化维护线程池 循环复用线程池里的线程 不用每次都新创建线程

  2. 在需要工人线程跑起来的时候 调用start

  3. 调用与执行分离开

  4. 可以自己通过传参数来确定工人线程的个数

public class Channel {
    private int workNums;
    private WorkThread[] threadPool;
    private int head;
    private int tail;
    private int count;
    private Request[] queue;

    public Channel(int workNums) {
        this.workNums = workNums;
        queue = new Request[workNums];
        initThreadPool();
    }
    private  void initThreadPool(){
        threadPool = new WorkThread[workNums];
        for (int i = 0; i < threadPool.length; i++) {
            threadPool[i]=new WorkThread(i, this);
        }
    }
    //不用新生成工作线程 直接工作
    public void startWorker() {
        for (WorkThread workThread : threadPool) {
            workThread.start();
        }
    }

    public synchronized void putRequest(Request request) throws InterruptedException {
        while (count >= workNums) {
            wait();
        }
        queue[tail] = request;
        tail = (tail + 1) % workNums;
        count++;
        notifyAll();
    }

    public synchronized Request getRequest() throws InterruptedException {
        while (count <= 0) {
            wait();
        }
        Request res = queue[head];
        head = (head + 1) % workNums;
        count--;
        notifyAll();
        return res;
    }
}


package ThreadPool;

/**
 * @author sqpstart
 * @create 2021-04-27 14:16
 */
public class Request {


    private  final String CompanyName;
    private  final Integer number;

    public Request(String compantName, Integer number) {
        CompanyName = compantName;
        this.number = number;
    }

    @Override
    public String toString() {
        return "Request{" +
                "CompanyName='" + CompanyName + '\'' +
                ", number=" + number +
                '}';
    }
    public void execute(){
        System.out.println(Thread.currentThread().getName()+"员工正在操作请求---->"+System.currentTimeMillis());
        System.out.println("请求来自客人"+this.toString());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"操作结束");
    }

}

package ThreadPool;

/**
 * @author sqpstart
 * @create 2021-04-27 14:25
 */
public class ClientThread extends  Thread {
    public ClientThread(Channel channel, String companyName) {
        this.channel = channel;
        this.companyName = companyName;
    }

    private final Channel channel;
    private final String companyName;


    @Override
    public void run() {
        try {
            for (int i = 0; true; i++) {
                channel.putRequest(new Request(companyName, i));
                Thread.sleep(10);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

package ThreadPool;

/**
 * @author sqpstart
 * @create 2021-04-27 14:51
 */
public class WorkThread extends  Thread{

    private  final Channel channel;

    public WorkThread(int workNo,Channel channel) {
        this.workNo = workNo;
        this.channel=channel;
    }

    private  final int workNo;

    @Override
    public void run() {
    //如果没有一直不停的处理请求 就会只有五次请求被处理了
      while(true) {
          try {
              Request request = channel.getRequest();
              request.execute();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
    }
}

在这里插入图片描述

真正的线程池 --使用线程池 防止每一个请求都创建一个线程 造成资源耗尽

我们已经很详细的模拟出线程池

  • 这个循环利用资源线程 不再开启线程
  • 队列满了 等待
    真实的线程池 就是还包括 队列满了 随时动态的新开线程 只要不打过max值
new ThreadPoolExecutor(…)

在这里插入图片描述

(1)、corePoolSize[5],核心线程数[一直存在,除非(allowCoreThreadTimeOut)];线程池,创建好以后就准备就绪的线程数量,就等待接收异步任务去执行

                   5个 Thread thread = new Thread(); thread.start();

(2)、maximumPoolSize[200]:最大线程数量;控制资源

(3)、keepAliveTime:存活时间。如果当前正在运行的线程数量大于core数量

                释放空闲的线程(maximumPoolSize-corePoolSize)。只要线程空闲大于指定的keepAliveTime;

(4)、unit:时间单位

(5)、BlockingQueue workQueue:阻塞队列。如果任务有很多。就会将多的任务放在队列里面

               只要有线程空闲,就会去队列里面取出新的任务继续执行

(6)、ThreadFactory:线程创建的工厂

(7)、RejectedExecutionHandler handler:如果队列满了,按照我们指定的拒绝策略,拒绝执行

在这里插入图片描述
在这里插入图片描述

使用 Executors创建线程池 常见有四种

cachedExecutors:

可以看到他没有核心线程 自己没有主动创建维护线程 也不会维护一个线程 只要请求变少 线程有空闲 都会被清空 直到清空为0
但是却对最大线程数没有设限 说明如果遇到高并发 该线程池没有对线程创建有控制
所以可以灵活的创建和回收线程
在这里插入图片描述

fixedThreadPool

指定线程个数 不会增长也不会减少 都不可回收
在这里插入图片描述

newScheduledThreadPool

delay 可以指定多长时间以后再来执行 定时任务线程池
在这里插入图片描述

newSingleThreadPool 单线程线程池 只有一个线程

在这里插入图片描述

使用线程池的优点

降低资源消耗 重复利用已经创建好的线程避免频繁地创建和摧毁带来的资源消耗

在这里插入图片描述

一个CPU上运行1000个线程 看起来是并行运行1000个线程 其实是并发 时间片轮询 一个时刻 只有一个线程轮到时间片在运行 其他线程都在等待

线程创建 销毁 以及线程上下文切换还要保存现场

无论从CPU还是线程 这些都告诉我们尽量不要频繁的创建和销毁大量线程

在这里插入图片描述
左侧是1000个 右侧是200个线程

提高响应速度 不用新启动线程 线程池中空闲线程都是处于就绪状态的 直接就能上场

在这里插入图片描述

便于管理 因为都在池中 可以根据多线程的业务分池 并在资源调度的时候关闭某一个池

在这里插入图片描述
如下面核心业务线程池 和 非核心业务线程池
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值