JavaEE线程安全实现线程池方法

前言:

线程虽然比进程更轻量,但是如果创建销毁的频率进一步增加,开销还是很大

解决方案:线程池or协程

线程池:把线程提前创建好放到池子里,后续用到线程直接从池子里取不必这边申请了。线程用完了也不是还给系统而是放回池子,以备下次再用。

为什么线程放在池子里就比从系统申请释放来得更快呢?

用户写的代码就是在最上面的应用程序来运行,这里的代码都称为“用户态”运行的代码,有些代码需要调用API进一步的逻辑就会在内核中执行。在内核中执行的代码称为“内核态”运行的代码。创建线程是在内核中创建PCB加到链表里,本身就需要内核的支持,调用Thread.start也是要在内核态上运行的。而创建好的线程放进池子里是用户态实现的,这个放进池里/从池子里取过程不涉及内核态,就是用户代码就能完成。一般认为纯用户态的操作效率要比内核态处理的操作效率更高。

java标准库中的线程池:

ThreadPoolExecutor需要java.util.concurrent包,Java中很多线程相关的组件都在concurrent包里

线程池构造方法:

ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)

线程池参数解析:

int corePoolSize 核心线程数(正式员工的数量)
int maximumPoolSize 最大线程数(正式员工+临时员工)
long keepAliveTime 允许临时工摸鱼的时间
TimeUnit unit 时间的单位(s,ms,us…)
BlockingQueue<Runnable workQueue 任务队列(线程池会提供一个submit方法让程序员把任务注册到线程池中,加到这个任务队列中)
ThreadFactory threadFactory 线程工厂(线程是怎么创建出来的)
RejectedExecutionHandler handler 拒绝策略
(当任务满了怎么做?1.直接忽略最新的任务 2.阻塞等待 3.直接丢弃最老的任务 …)

一个程序要并发的/多线程的来完成一些任务,如果使用线程池的话这里线程数量多少合适?

通过测试性能找到合适的值,例如,写一个服务器程序通过线程池,多线程处理用户请求就可以对这个服务器性能经行测试。比如每秒发送500/1000/2000的请求…
根据不同线程池的线程数来观察程序处理任务的速度和程序持有的CPU的占用率。当线程数量多了整体速度是会变快但是CPU占用率也会高,当线程数少了整体速度会变慢但是Cpu占用率也会下降。
需要找到一个让程序速度能接受并且CPU占用也合理的平衡点,不同类型的程序单个任务在CPU上计算时间和阻塞时间的分布是不相同的,因此不是一个确定的数字。

简化版的线程池:

Executors本质是针对ThreadPoolExecutor进行了封装提供了一些默认参数。

public class 线程池 {
    public static void main(String[] args) {
        // 创建一个固定线程数目的线程池. 参数指定了线程个数
        ExecutorService pool = Executors.newFixedThreadPool(10);

        //创建一个自动扩容的线程池,会根据任务量来进行自动扩容
        Executors.newCachedThreadPool();

        //创建一个只有一个线程的线程池
        Executors.newSingleThreadExecutor();

        //创建一个带有定时器功能的线程池,类似于Timer
        Executors.newScheduledThreadPool(10);

        for (int i = 0; i < 100; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("hello threadpool");
                }
            });
        }

    }
}

线程池的组成:

  • 1.先能够描述任务(直接使用Runnable)
  • 2.需要组织任务(直接使用BlockingQueue)
  • 3.能够描述工作线程
  • 4.还需要组织这些线程
  • 5.需要实现往线程里添加任务
class MyThreadPool{
    //1.先描述一个任务,直接使用Runnable不需要产生额外类
    //2.使用一个数据结构来组织若干任务
        private BlockingQueue<Runnable> queue= new LinkedBlockingDeque<>();
    //3.描述一个线程,工作线程的功能就是从任务队列中取任务并执行
    static class Worker extends Thread{
        //当前线程池中有若干个Worker线程,这些线程内部都持有了上述的任务队列
        private BlockingQueue<Runnable> queue = null;
        public Worker(BlockingQueue<Runnable> queue){
            this.queue = queue;
        }

        @Override
        public void run() {
            //就需要能够拿到上面的队列
            while(true){

                try {
                    //循环的去获取任务队列中的人物
                    //这里如果队列为空就直接阻塞,如果队列非空就获取到里面的内容
                    Runnable runnable = queue.take();
                    //获取到后就执行
                    runnable.run();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //4.创建一个数据结构来组织若干个线程
    private List<Thread> workers = new ArrayList<>();
    public MyThreadPool(int n){
        //在构造方法中创建若干个线程放到上述数组中
        for (int i = 0; i < n; i++) {
            Worker worker = new Worker(queue);
            worker.start();
            workers.add(worker);
        }
    }

    //5.创建一个方法,能够允许程序员来放任务到线程池中
    public void submit(Runnable runnable){
        try {
            queue.put(runnable);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
public class 我的线程池 {
    public static void main(String[] args) {
        MyThreadPool pool = new MyThreadPool(10);
        for (int i = 0; i < 100; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("hello threadpool");
                }
            });
        }
    }
}

到此这篇关于JavaEE线程安全实现线程池方法的文章就介绍到这了,更多相关JavaEE线程安全 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 2020新版idea创建项目没有javaEE 没有Web选项的完美解决方法

    正常创建java项目 然后右击 点击第二个,添加框架 就可以看到啦 勾选web点击apply ok 就可以啦 总结 到此这篇关于2020新版idea创建项目没有javaEE 没有Web选项的完美解决方法的文章就介绍到这了,更多相关idea创建项目没有javaEE 没有Web选项内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

  • JavaEE的进程,线程和创建线程的5种方式详解

    目录 一.认识进程.线程 1.1什么是进程 进程的调度 并发式执行 1.2认识线程 1.3进程.线程之前的区别和联系(面试题) 创建线程的几种方式 总结 一.认识进程.线程 1.1什么是进程 进程process/task.“进程"是计算机完成一个工作的"过程” 设备上一个正在运行的程序,就是一个进程.比如你打开的QQ就是一个进程,正在和别人聊天的微信也是一个进程.进程是系统进行资源分配的基本单位. 当我们打开任务管理器就可以看到,当前操作系统中正在运行的进程. 要想让一个进程真正的运行

  • JavaEE实现基于SMTP协议的邮件发送功能

    本博客介绍基于SSM框架(Spring4.0+SpringMVC+Mybatis)组合的Javamail应用,邮箱的话基于腾讯的QQ邮箱,其实也是Foxmail邮箱 先要了解一下SMTP协议和SSL加密 SMTP:称为简单邮件传输协议(Simple Mail Transfer Protocal),目标是向用户提供高效.可靠的邮件传输.SMTP是一种请求响应的协议,也就是客户机向远程服务器发送请求,服务器响应,监听端口是25,所以其工作模式有两种:发送SMTP,接收SMTP SSL加密:用来保障浏

  • JavaEE SpringMyBatis是什么? 它和Hibernate的区别及如何配置MyBatis

    MyBatis MyBatis 是一个基于 Java 的持久层框架.MyBatis 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAO),它消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索. MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录. 目前,Java 的持久层框架产品有许多,常见的有 Hiber

  • 详解JavaEE 使用 Redis 数据库进行内容缓存和高访问负载

    NoSQL(Not Only SQL),泛指非关系型数据库,是为了处理高并发读写.海量数据的高效率存储和访问.高扩展性和高可用性而产生的. 分类 相关产品 典型应用 数据模型 优点 缺点 键值对(Key-Value)存储 Redis.Voldemort.Berkeley DB 内容缓存.处理高访问负载 一系列键值对 快速查询 存储的数据缺少结构化 列存储数据库 Cassandra.HBase.Riak 分布式文件系统 以列簇式存储,将同一列数据存在一起 查询速度快,可扩展性强,更容易进行分布式扩

  • JavaEE Spring MyBatis如何一步一步实现数据库查询功能

    配置好一个SptingBoot项目配置好MyBatis JavaEE Spring~MyBatis是什么? 它和Hibernate的区别有哪些?如何配置MyBatis? SpringBoot配置文件application.properties简单介绍 确保MyBatis配置正确 手动实现一个xml文件 上面我是用的是一个自定义的接口 此时没有它对应的xml文件 此时我们需要 下图中column表示查询列, property表示返回类型中的属性 在Controller中进行测试 package l

  • 详解JavaEE中Apollo安装使用小结

    目录 一.安装MySQL5.7.37(主机:192.168.233.128,用户/密码:root): 二.Apollo安装/启动(centos7)(主机:192.168.233.128): 三.Web应用接入Apollo(SpringBoot): 说明: Apollo是配置管理中心,和SpringCloud-Config实现的功能有点相似. 一.安装MySQL 5.7.37(主机:192.168.233.128,用户/密码:root): 1.下载mysql-5.7.37-1.el7.x86_64

  • JavaEE线程安全定时器模式任务

    目录 前言 1.描述任务 2.组织任务 3.执行时间到了的任务 前言 像是一个闹钟定时,在一定时间之后被唤醒并执行某个之前设定好的任务,join(指定超时时间),sleep(指定休眠时间)都是基于系统内部的定时器来实现的.java.util.Timer核心方法就一个,schedule参数有两个:任务是啥(一段代码),多长时间之后执行 public class 定时器 {     public static void main(String[] args) {         Timer time

  • JNDI在JavaEE中的角色_动力节点Java学院整理

    虽然 J2EE 平台提高了普通企业开发人员的生活水平,但是这种提高是以不得不学习许多规范和技术为代价的,这些规范和技术则是 J2EE 为了成为无所不包的分布式计算平台而整合进来的.Dolly Developer 是众多开发人员中的一员,她已经发现了一个特性,该特性有助于缓解随企业级应用程序部署而带来的负担,这个特性就是 JNDI,即 Java 命名与目录接口(Java Naming and Directory Interface).让我们来看看 Dolly 在没有 JNDI 的时候是怎么做的,以

  • 详解Javaee Dao层的抽取

    有时候我们在实现不同功能的时候回看到很多的Dao层的增加.修改.删除.查找都很相似,修改我们将他们提取BaseDao 一.提取前 1. 提取前的LinkDao层: public interface LinkManDao { Integer findCount(DetachedCriteria detachedCriteria); List<LinkMan> findByPage(DetachedCriteria detachedCriteria, Integer startIndex, Int

随机推荐