多线程(Java系列6)

news2024/9/28 18:04:52

目录

前言:

1.什么是线程池

2.标准库中的线程池

3.实现线程池

结束语:


前言:

在上一节中小编带着大家了解了一下Java标准库中的定时器的使用方式并给大家实现了一下,那么这节中小编将分享一下多线程中的线程池。给大家讲解一下什么是“池”,为什么要使用线程池。

1.什么是线程池

之前我们也有讲过“池”这个概念,我们讲过字符串常量池,数据连接池...

线程池就是提前把线程准备好,创建线程不是直接从系统中申请而是从池子中拿,当线程不用了的时候也是还给池子。它存在的目的就是为了提高效率,它最大的好处就是减少每次启动、销毁线程的损耗。线程的创建虽然比进程轻量,但是在频繁的创建的情况下,开销也是不可忽略的。

那么为什么从池子里拿比创建线程要更高效呢?

  • 从线程池拿线程,纯粹的用户态操作。
  • 从系统创建线程,涉及到用户态内核态之间的切换。真正的创建是要在内核态完成。

在上述过程中提到了用户态、内核态这两个概念,那么下来给大家解释一下什么是用户态,什么是内核态。

一个操作系统 = 内核 + 配套的应用程序

  • 其中内核就是操作系统中最核心的功能模块的集合,里面有硬件管理、各种驱动、进程管理、内存管理、文件系统...
  • 内核则需要给上层的应用程序提供支持。

比如我们执行:println("hello")这样的一个操作。

首先应用程序调用系统内核,告诉内核我要进行打印一个字符串的操作,内核再通过驱动程序,操作显示器来完成上述的请求。应用程序有很多,但是内核只有一个,内核要给这么多程序提供服务有的时候服务就不会那么及时。

举一个例子:比如银行里的工作人员和来银行办理事务的人,假设工作人员只有一个人,客户有很多,此时工作人员就相当于内核,客户就是用户。工作人员待的柜台就是用户态,银行的大厅就是用户态。如下图所示:

滑稽A此时来到柜台给工作人员说:我想办张银行卡。

此时就需要复印一些文件,这时我们有两种解决办法:

  1. A滑稽自己去大厅的复印机去复印,然后拿给工作人员。
  2. 工作人员去柜台里面的复印机去复印。

那么此时如果A滑稽自己去复印的话速度就会很快,立即复印,立即回来。但是如果是工作人员去复印的话可能就会很慢,因为柜台只有它一个人,他可能还需要给其他人提供服务。所以这也就例比于我们计算机中的用户态操作和内核态操作了,A滑稽自己复印就是用户态操作,而工作人员复印就是内核态操作。

结论:纯用户态操作,时间是可控的。涉及到内核态操作,时间就不太可控了。

2.标准库中的线程池

Java标准库中提供了线程的线程池。

ExecutorService pool = Executors.newFixedThreadPool(10);

 在这里我们可以看到和我们之前创建一个对象不太一样。

注意:这里我们使用的是工厂模式!!!

创建对象的时候不再直接new,而是使用一些其他方法(通常是静态方法)协助我们把对象创建出来。

Executors.newFixedThreadPoll()是不会设定固定值的,这里是按需创建,用完之后也不会立即销毁,留着以备后用。

下面我们来给大家演示一下:
代码展示:

package Time;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//线程池的使用
public class ThreadDemo3 {
    public static void main(String[] args) {
        //创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool(10);
        //添加任务到线程池中
        pool.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
        });
    }
}

结果展示:

说道这里我们就不得不去看一下Java的官方文档中对线程池的解释了。

我打开Java的官方文档,没有的同学可以点击这个链接进入☞Java Platform SE 8

进入之后点击下面的进入ThreadPoolExecutor的页面。

 我们可以看到它的参数有以下几个:

我们分别给大家解释一下:

  • corePollSize:核心线程数,如果类比一家公司的话,那么他们就是公司里面的正式员工。
  • maximumPollSize:最大线程数,相当于是公司中的正式员工+实习生。如果当前的任务比较多,线程池就会多创建一些“临时线程”。如果当前任务比较少,比较空闲了,线程池就会把多创建出来的临时线程给销毁。也就相当于在公司里面如果任务比较多的话就多招几个实习生,但是如果任务不多的话就辞退实习生,保留正式员工。
  • KeepAliveTime:线程的存活时间,如果任务不多了,那么临时创建的线程也不是一下子就销毁的,而是保留一段时间在销毁,相当于是在公司中,如果任务不多的话,实习生也不是瞬间就被辞退了,而是观察一段时间,看公司是不是长时间要处于一个不忙的状态。
  • unit:时间单位。
  • workQueue:线程池也要管理很多任务,这些任务也是通过阻塞队列来组织的,程序猿可以手动指定给线程池一个队列,此时程序猿就很方便的可以控制/获取队列中的信息了,submit方法其实就是把任务放到该队列中。
  • threadFactor:工程模式,创建线程的辅助的类。
  • handler: 线程池的拒绝策略,如果线程池的池子满了,继续往里添加任务,那么该如何进行拒绝呢?我们接着往下看。

关于线程池的拒绝策略,标准库给我们提供了四种。

下面来给大家分别解释一下:

  • ThreadPoolExecutor.AbortPolicy:表示如果任务满了,继续添加任务,添加的操作就会直接抛出异常。
  • ThreadPoolExecutor.CallerRunsPolicy:添加的线程自己负责执行这个任务。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃最老的任务。
  • ThreadPoolExecutor.DiscardPolicy:丢弃最新的任务。

3.实现线程池

下面我们就自己来实现一个线程池。

代码展示:

package Time;

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

//自己实现的线程池
class MyThreadPool{
    //阻塞队列用来存放任务
    private BlockingDeque<Runnable> queue = new LinkedBlockingDeque<>();
    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }

    //此处实现一个固定线程数的线程池
    public MyThreadPool(int n) {
        for (int i = 0; i < n; i++) {
            Thread t = new Thread(() -> {
                try {
                    while (true) {
                        //此处需要让线程池内部有一个while循环,不停的取任务
                        Runnable runnable = queue.take();
                        runnable.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t.start();
        }
    }
}
public class ThreadDemo4 {
    public static void main(String[] args) throws InterruptedException {
        MyThreadPool pool = new MyThreadPool(10);
        for (int i = 0; i < 1000; i++) {
            int number = i;
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("hello " + number);
                }
            });
            Thread.sleep(3000);
        }
    }
}


结果展示:

此处我们可以看到,线程池中任务的执行顺序和添加顺序不一定是相同的,这是非常正常的,因为这是个线程的调度是无序的。 

结束语:

这节小编就与大家分享到这里啦,这节中小编主要与大家分享了什么是线程池,带着大家一起看了标准库中的线程池,并且我们自己还实现了一遍,希望这节对大家线程池有一定了解,想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/803637.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ucore lab6 调度管理机制

练习0&#xff1a;填写已有实验 具体更改的地方如下&#xff1a; proc.c 中alloc_proc新增加内容 proc->rq NULL;list_init(&proc->run_link);//proc->run_link.next proc->run_link.prev NULL ;proc->time_slice 0;proc->lab6_run_pool.left pro…

探索网页原型设计:构建出色的用户体验

在当今数字化时代&#xff0c;用户对网页体验的要求日益提高。在网页设计过程中&#xff0c;扮演着至关重要的角色。通过网页原型设计&#xff0c;产品经理能够更好地展示和传达网页的整体布局、导航结构、元素位置和交互效果&#xff0c;从而使团队成员更清晰地了解设计意图&a…

2023年最佳咨询项目管理软件推荐,助力项目顺利进行!

咨询项目管理软件哪个好&#xff1f;用顾问的终极项目管理软件Zoho Projects的咨询软件管理知识库&#xff0c;简化流程让客户满意。 一、加强您的咨询项目管理 1、简化客户管理 通过多合一平台超越客户期望。管理客户请求、组织文件并保护机密数据。 2、跟踪您的整个投资组…

FinalShell docker容器mysql:中文显示乱码

FinalShell 中文显示乱码 在FinalShell 执行 select 语句发现表格&#xff0c;发现中文显示的问号 解决方法&#xff1a; mysql default-character-set utf8mb4 -p1234这个方法是&#xff0c;可以登录直接显示中文&#xff0c;但是在修改&#xff0c;输入中文还是不能解决。 如…

电赛培训(高频电路类赛题)学习总结

此篇文章基于全国电子设计大赛培训网的官网的高频电路类赛题总结的知识点。 高频电路赛题的相关理论知识点 &#xff08;1&#xff09;高频电路的单位 a.1kHz1000Hz不等于1KHz&#xff08;大写的K是错误的&#xff09; b.S是西门子&#xff0c;电导的单位&#xff0c;s是秒&…

5G时代的APP开发:机遇与挑战

APP开发是互联网行业中的重要组成部分&#xff0c;随着5G时代的到来&#xff0c;移动 APP开发也迎来了新的机遇和挑战。 5G时代不仅会为移动 APP开发带来新的发展机遇&#xff0c;也会给移动 APP开发带来新的挑战。对于企业和开发者而言&#xff0c;5G时代带来的机遇和挑战是并…

C语言程序设计——程序环境和预处理

一、翻译环境 &#xff08;1&#xff09;组成一个程序的每个源文件&#xff0c;通过翻译过程分布转换成对应的目标代码&#xff1b; &#xff08;2&#xff09;每个目标文件由链接器链接到一起&#xff0c;形成一个单一而完整的可执行程序&#xff1b; &#xff08;3&#xf…

基于ESP8266+网络调试助手点灯实验

文章目录 ESP8266串口wifi模块简介实验准备硬件接线程序下载注意事项总结 ESP8266串口wifi模块 简介 ESP8266 是一种低成本、高性能的 Wi-Fi 模块&#xff0c;内置了 TCP/IP 协议栈&#xff0c;它可以作为单独的无线网络控制器&#xff0c;或者与其他微控制器进行串口通信。它…

Linux之 Vim 搜索方式

方式一&#xff1a;快速搜索&#xff08;字符串完全匹配&#xff0c;区分大小写&#xff09; 格式&#xff1a; / 关键词 or &#xff1f; 关键词 /内容 #按回车键搜索 从上到下查找 ?内容 #按回车键搜索 从下到上查找 优点&#xff1a;快速定位到该关键字 回车之后&…

Spark(37):Streaming DataFrame 和 Streaming DataSet 创建

目录 0. 相关文章链接 1. 概述 2. socket source 3. file source 3.1. 读取普通文件夹内的文件 3.2. 读取自动分区的文件夹内的文件 4. kafka source 4.1. 导入依赖 4.2. 以 Streaming 模式创建 Kafka 工作流 4.3. 通过 Batch 模式创建 Kafka 工作流 5. Rate Source…

回归预测 | MATLAB实现PSO-GPR粒子群优化高斯过程回归多输入单输出回归预测

回归预测 | MATLAB实现PSO-GPR粒子群优化高斯过程回归多输入单输出回归预测 目录 回归预测 | MATLAB实现PSO-GPR粒子群优化高斯过程回归多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab基于PSO-GPR基于粒子群算法优化高斯过程回归的数据回归预…

Jmeter经过处理的变量设置全局变量

之前遇到一个问题&#xff1a;项目的某些接口是需要登录的而且登录不能多用户登录。模拟登录的时候传入请求头的其中一个参数比较复杂&#xff0c;需要登录后的某些参数拼接和加密后设置成全局变量&#xff0c;在请求头中调用这个变量&#xff0c;正常的设置全局变量的方法百度…

Java NIO 详解

Java 从1.4开始引入NIO&#xff08;New IO&#xff09;&#xff0c;是一种基于块&#xff08;Block&#xff09;的IO机制&#xff0c;也称为非阻塞IO。相比于传统的Java IO&#xff08;IO流&#xff09;方式&#xff0c;Java NIO提供了更快速、高效、灵活的IO操作。 Java NIO的…

一文让你彻底搞懂Mybatis之缓存机制

编译软件&#xff1a;IntelliJ IDEA 2019.2.4 x64 操作系统&#xff1a;win10 x64 位 家庭版 Maven版本&#xff1a;apache-maven-3.6.3 Mybatis版本&#xff1a;3.5.6 文章目录 一. 缓存是什么&#xff1f;二. 为什么要使用缓存&#xff1f;三. Mybatis中的缓存分哪几种&#…

自己实现MyBatis 底层机制--抽丝剥茧(上)

&#x1f600;前言 本篇博文是学习过程中的笔记和对于MyBatis底层机制的分析思路&#xff0c;希望能够给您带来帮助&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到…

Base64之间的相互转化

使用org.apache.ommons.codec.binary.Base64实现字符串和Base64之间的相互转化 字符串转化为Base64之间的相互转化一 //转化为Base64字符串 String strOld "Welcome to the new world"; base64EncodeStr Base64.encodeBase64String(strOld.getBytes()); System.o…

黑马点评项目学习笔记(15w字详解,堪称史上最详细,欢迎收藏)

黑马点评项目学习笔记 文章目录 黑马点评项目学习笔记前言项目搭建导入数据库初始化项目启动项目启动前端项目启动后端项目 基于Session实现短信验证码登录短信验证码登录配置登录拦截器数据脱敏 Session集群共享问题基于Redis实现短信验证码登录短信验证登录配置登录拦截器 店…

漏洞分析|Metabase 代码执行漏洞(CVE-2023-38646):H2 JDBC 深入利用

0x01 概述 最近 Metabase 出了一个远程代码执行漏洞&#xff08;CVE-2023-38646&#xff09;&#xff0c;我们通过研究分析发现该漏洞是通过 JDBC 来利用的。在 Metabase 中兼容了多种数据库&#xff0c;本次漏洞中主要通过 H2 JDBC 连接信息触发漏洞。目前公开针对 H2 数据库…

国产内存强势崛起,光威神条有神价,无套路闭眼可入

今年的DIY电脑市场终于摆脱了前两年的阴霾&#xff0c;从CPU到内存都有着充足的货源&#xff0c;而且价格靠谱&#xff0c;特别是国产存储品牌超级厚道&#xff0c;内存、硬盘等配件的价格基本都是大跳水&#xff0c;相比于去年&#xff0c;同样的价格能够买到容量和性能翻倍的…

ERROR 1064 - You have an error in your SQL syntax;

ERROR 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near (/, 少个逗号吧&#xff0c;以前开始写SQL&#xff0c;特别是修改SQL的时候容易出现这样错误。 而且自己也知道在附近…