Java多线程案例之线程池

news2024/9/21 2:40:36

前言:在讲解线程池的概念之前,我们先来谈谈线程和进程,我们知道线程诞生的目的其实是因为进程太过重量了,导致系统在 销毁/创建 进程时比较低效(具体指 内存资源的申请和释放)。

而线程,其实做到了共享内存资源,新的线程复用之前的资源(也就不必再申请了)。

但是如果线程创建的速率进一步的频繁,此时线程创建销毁的开销仍然不能忽略,这时就需要线程池来进一步优化这里的速度了。

一、介绍线程池

线程池是一种线程使用模式。当线程过多时会带来调度开销,进而影响缓存局限性和整体性能。

线程池维护这多个线程,等待监督管理分配可并发执行的任务,避免了处理短时间任务时创建与销毁线程的代价,线程池不仅能保证内核的充分利用,还能防止过分调度。

为什么线程池比创建新线程快?

首先我们要明白线程池中取线程的过程,池中的线程执行任务时候,不需要再重新创建线程,而是直接从池子里取出一个现成的线程,直接使用,使用之后并非销毁,而是放回到线程池中。

回到上面的问题,那为什么直接取一个现成的线程要快一点呢?

:可能有人会回答,创建线程需要申请资源,因此利用现有的线程池比创建线程更轻量,虽然创建线程确实是有申请资源,但这并不是最主要的。

那就先说结论吧,使用线程池是纯用户态操作,而创建线程需要经历用户态到内核态的转变。因此,线程池这种纯用户态要比后者快。

用户态:每个线程都自己执行自己的逻辑。

内核态;一个系统只有这一份内核在执行逻辑,这个内核需要给所有的进程提高服务。

下面进一步讲解线程和线程池的运作过程:

创建线程:我们知道线程本质上是PCB(内核中的数据结构),当应用程序发起一个 创建线程 的行为,应用程序就需要通过系统调度,进入到操作系统内核中执行,内核完成PCB的创建之后,再把PCB加入到调度队列中,之后再返回给应用程序。

线程池:从线程池中取线程,把线程放回线程池,都在操作系统内核中实现,这是纯用户态实现的逻辑,用户态的每个进程都是自己执行自己的逻辑,运行较快。

 二、标准库中的线程池

标准库中我们一般通过工厂模式(不通过new关键字而使用工厂类来创建对象,能够让创建对象变得简单而且更方便的修改对象,属于创建型模式。)的方法来创建线程池:

//此处创建线程池,没有显示的new,而是通过另外Executors类的静态方法newCachedThreadPool来完成
//这种做法叫做工厂模式,对应此处的newCachedThreadPool()方法就是工厂方法。
        ExecutorService pool = Executors.newCachedThreadPool();

为何需要使用工厂模式创建线程而不使用常见的 构造方法呢?

因为构造方法常见的提供多种构造实例的方式是:重载,而重载要求 参数的个数/类型 不同。

这就带来了一些限制。

比如:

此处的两个版本的构造方法就无法形成重载。解决这个问题就是使用普通方法来代替构造方法,使普通方法在里面分别构造Point对象,再通过一些其他手段进行设置即可。

线程池单纯的使用也是非常简单,使用submit方法,把任务交给线程池即可,线程池中会有一些线程来负责完成这里的任务。

        ExecutorService pool = Executors.newCachedThreadPool();
        pool.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
        });

三、模拟实现线程池

我们知道一个线程池可以同时提交N个任务,对应的线程池中有M个线程来负责完成这N个任务。

可能会有人问,为什么N个任务不对应N个线程来完成任务呢?

这时因为如果这样设置的话,由于开发中很多时候任务难度是不同的,如果设置N对N关系的话,可能会出现有的线程很早就完成任务了,然后就在旁边干等着,造成 一个线程干活,多个线程围观的场面,这是很尴尬的。

如何把N个任务分配给M个线程执行呢?

利用生产者消费者模型即可,首要步骤就是实现一个阻塞队列,每个被提交的任务,都被放入阻塞队列中,让M个线程来取队列中的元素,如果队列为空,M个线程就阻塞等待,如果队列不为空,每个线程就来领取任务,执行完手头上的任务时,再去取下一个任务,直到队列为空,线程继续阻塞等待。

代码实现:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;


class MyThreadPool {
    private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();

    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }

    public MyThreadPool(int m) {
        //在构造方法中,创建出M个线程,负责完成工作。
        for (int i = 0; i < m; i++) {
            Thread t = new Thread(() -> {
                while(true) {
                    try {
                         Runnable runnable = queue.take();
                         runnable.run();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        }
    }
}
public class Demo25 {
    public static void main(String[] args) throws InterruptedException {
        MyThreadPool pool = new MyThreadPool(10);
        for (int i = 0; i < 1000; i++) {
            int taskId = i;
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("执行当前任务"+taskId+"当前线程"+Thread.currentThread().getName());
                }
            });
        }
    }
}

运行结果:

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

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

相关文章

14岁初中生将免去四考,保送清华本硕博连读,乡亲们敲锣打鼓祝贺

导语&#xff1a; 很多学生在很小的时候&#xff0c;都曾有豪言壮语&#xff1a;“将来一定要考上清华北大”。可是真正接受教育&#xff0c;开始学习之后&#xff0c;学生们才能发现&#xff0c;原来学习这么难。不要说真的走进清华北大&#xff0c;即使是进入“985”大学&am…

C++ 智能指针(一) auto_ptr

文章目录前言 - 什么是智能指针&#xff1f;std::auto_ptrauto_ptr的使用常用成员方法&#xff1a;1. get()方法2. release()方法3. reset()方法4. operator()5. operator*() & operator->()auto_ptr的局限性前言 - 什么是智能指针&#xff1f; 在全文开始之前&#xf…

Redis事务的概述、设计与实现

1 Redis事务概述事务提供了一种“将多个命令打包&#xff0c; 然后一次性、按顺序地执行”的机制&#xff0c; 并且事务在执行的期间不会主动中断 —— 服务器在执行完事务中的所有命令之后&#xff0c; 才会继续处理其他客户端的其他命令。以下是一个事务的例子&#xff0c; 它…

mysql-事务以及锁原理讲解(二)

1、前言 众所周知&#xff0c;事务和锁是mysql中非常重要功能&#xff0c;同时也是面试的重点和难点。本文会详细介绍事务和锁的相关概念及其实现原理&#xff0c;相信大家看完之后&#xff0c;一定会对事务和锁有更加深入的理解。 2、什么是事务 在维基百科中&#xff0c;对事…

7 处理多维特征的输入

文章目录课程前提知识问题引入模型改进修改神经层的增加学习能力与超参数课本代码课程来源: 链接课程文本来源借鉴&#xff1a; 链接以及&#xff08;强烈推荐&#xff09;Birandaの课程前提知识 BCELoss - Binary CrossEntropyLoss BCELoss 是CrossEntropyLoss的一个特例&am…

JavaEE day7 初识JavaScript2

函数小结 1.可以赋值给变量(其实就是被变量所指向) 2.装入容器中作为元素存在 3.在函数调用的过程中&#xff0c;函数类型作为实参 4.函数作为另一个函数的返回值 可以直接return一个函数 5.和java不同&#xff0c;JS中允许在一个函数中定义另一个函数&#xff0c;也就是嵌…

介绍一个令强迫症讨厌的小红点组件

前言 在 App 的运营中,活跃度是一个重要的指标,日活/月活……为了提高活跃度,就发明了小红点,然后让强迫症用户“没法活”。 小红点虽然很讨厌,但是为了 KPI,程序员也不得不屈从运营同学的逼迫(讨好),得想办法实现。这一篇,来介绍一个徽标(Badge)组件,能够快速搞…

解决OpenEuler系统 Minimal BASH-like line editing is supported

2023年开工解决的第一个问题~呃&#xff0c;起因是这样的&#xff0c;由于业务需要&#xff0c;修改内核参数后重新打包内核&#xff0c;然后安装内核rpm包后&#xff0c;强制关机&#xff0c;结果就出现如上界面。网上搜索后绝大部分是因为安装了双系统后找不到grub系统引导文…

ELK_Elasticsearch基础介绍

目录 一、搜索是什么&#xff1f; 二、数据库做搜索的弊端 三、全文检索、倒排索引和Lucene 四、什么是Elasticsearch 1、Elasticsearch的功能 2、Elasticsearch的使用场景 3、Elasticsearch的特点 五、elasticsearch核心概念 一、搜索是什么&#xff1f; 概念&#x…

vue2与vue3面试题之区别

目录vue2与vue3面试题之区别01&#xff1a;数据双向绑定&#xff08; proxy 替代 defineProperty&#xff09;02&#xff1a;生命周期函数的更换03&#xff1a;vue3的新特性04&#xff1a;缓存组件与更新组件05&#xff1a;ref和reactive的区别06&#xff1a;watch和watchEffec…

测试篇(五):什么是自动化测试、自动化测试分类、selenium工具、第一个自动化测试程序

目录一、什么是自动化测试二、自动化测试分类2.1 单元测试2.2 UI自动化测试三、selenium工具3.1 selenium的介绍3.2 环境部署3.3 selenium的常用方法四、第一个自动化测试用例一、什么是自动化测试 在日常生活中我们会见到&#xff0c;自动化的水龙头、无人驾驶汽车、自动化的…

Mysql,使用FIND_IN_SET()函数处理多表关联问题.

这里有 user表、teacher表&#xff0c;其中 teacher.user_ids 字段中的值是 user.id 值以英文半角逗号拼接而来。现在&#xff0c; 我们需要在查询 teacher 表数据时&#xff0c;将 user.name 的值也查询出来。使用以下的SQL语句&#xff0c;即可实现需求。SELECTGROUP_CONCAT(…

系统编程中的进程的概念No.1

引言&#xff1a; 北京时间2023/1/28&#xff0c;本小编04年1月9日出生&#xff0c;今天第一次理解到进程的概念&#xff0c;所以我们接下来就学习一下什么是进程以及和进程相关的一些知识。首先我们想要了解进程以及其相关的知识&#xff0c;我们要先理解一下其它方面的知识&…

【2】Linux基础命令

学习笔记目录 初识Linux--入门Linux基础命令--会用Linux权限管控--懂权限Linux实用操作--熟练实战软件部署--深入掌握脚本&自动化--用的更强项目实战--学到经验云平台技术--紧跟潮流 Linux的目录结构 Linux的目录结构是一个树形结构&#xff0c;没有盘符这个概念&#x…

常用算法分类

按照使用场景分类排序算法&#xff0c;如冒泡排序&#xff0c;快速排序等&#xff0c;用于将一组数据按照特定规则排序。搜索算法&#xff0c;如二分查找算法&#xff0c;深度优先搜索算法等&#xff0c;用于在一组数据中查找特定元素。图论算法&#xff0c;如最短路径算法&…

Claude的2022年终总结——关于2022和Claude的四个问题

文章目录前言1. 我算是合格的开发者了吗2. 我算是正式的游戏人了吗3. 我算是成熟的社会人了吗4. 我算是什么样的写作者呢最后前言 2022年的这个时候&#xff0c;我也是在准备着年终总结&#xff0c;只不过应公司要求&#xff0c;准备述职晋升&#xff0c;是抱着升职加薪&#…

行为型模式 - 命令模式Command

模式的定义与特点 命令模式&#xff08;Command Pattern&#xff09;&#xff0c;是将一个请求封装成一个对象&#xff0c;从而使您可以用不同的请求对客户进行参数化。命令模式是把发出命令的责任和执行命令的责任分割开&#xff0c;委派给不同的对象。命令模式允许请求的一方…

设计一个消息队列的思考点

导图所以主要考虑的点是&#xff1a;P1.1. MQ 要有基础的消息管理能力&#xff08;CRUD&#xff09;P1.2. MQ 要有产消日志P2. MQ将消息存储成功才能响应成功P3.1 MQ将消息存储 分片存储P3.2 扩容的实现思路(如何在扩容的时候更方便高效)P4.1 数据要有副本&#xff08;分片副本…

【27】C语言 | 指针进阶

目录 一、指针概念 二、字符指针 三、指针数组 四、数组指针 五、数组参数、指针参数 六、函数指针 七、函数指针数组 八、回调函数 一、指针概念 1.指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间。2.指针的大小是固定的4/8个字节(32位平…

Java ccflow 代码

草稿规则目录概述需求&#xff1a;设计思路实现思路分析1.URL管理参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,challenge Survive. happ…