线程池实现原理及案列

源码分析RocketMQ顺序消息消费实现原理 我个人认为,如果你想靠着背面试题来获得心仪的offer,用癞蛤蟆想吃天鹅肉形容完全不过分。想必大家能感受到面试越来越难,想找到心仪的工作也是越来越难,高薪工作羡慕不来,却又对自己目前的薪资不太满意,工作几年甚至连一个应届生的薪资都比不上,终究是错付了,错付了自己没有去提升技术。这些面试题分享给大家的目的,其实是希望大家通过大厂面试题分析自己的技术栈,给自己梳理一个更加明确的学习方向,当你准备好去面试大厂,你心里有底,大概知道面试官会问多广,多深,避免面试的时候一问三不知。 阅读详情

一、原理图

这里写图片描述

我们都知道,线程池和多线程的区别就是一个是业务来了动态地去产生线程,一个是把线程事先产生出来放到一个池子中,当要使用线程的时候,从池子中拿出来,当用完后,再把线程放回池子中,但它远远没有这么简单。首先看看原理图,当客户端请求连接时,服务器监听到之后会将其放入到任务队列中,线程再从任务队列中拿走任务,这是两个典型的生产者消费者模型。对于后面的线程池来说,一开始初始化的时候,根据设计的不同,回去限定线程的最大个数,最小个数,初始化多少个等等。

例如:

int min_thr_num;                    /*线程组内默认最小线程数*/
int max_thr_num;                    /*线程组内默认最大线程数*/
int live_thr_num;                   /*当前存活线程个数*/
int busy_thr_num;                   /*忙状态线程个数*/
int wait_exit_thr_num;              /*要销毁的线程个数*/

监控线程的任务也是简单明了,一般情况就是根据一定的算法去动态的产生于销毁线程。

例如:

GetAllNum表示获取线程池所有的线程数,m_iInitNum 表示初始化的线程数量,iAvailNum 工作的线程数,m_iMaxNum最大线程数,m_iAvailHigh工作线程的最高数量
 if(iAvailNum < m_iAvailLow)
  {
    if(GetAllNum() + m_iInitNum - iAvailNum < m_iMaxNum)
    {
        CreateIdleThread(m_iInitNum - iAvailNum);
    }
    else
    {
      CreateIdleThread(m_iMaxNum - GetAllNum());
    }
  }
  else if(iAvailNum > m_iAvailHigh)
  {
      DeleteIdleThread(1);
  }

或

void *adjust_thread(void *threadpool)
{
   int i;
    threadpool_t *pool = (threadpool_t *)threadpool;
    while (!pool->shutdown) {
    sleep(DEFAULT_TIME);                                    /*延时10秒*/
    pthread_mutex_lock(&(pool->lock));
    int queue_size = pool->queue_size;
    int live_thr_num = pool->live_thr_num;
    pthread_mutex_unlock(&(pool->lock));

    pthread_mutex_lock(&(pool->thread_counter));
    int busy_thr_num = pool->busy_thr_num;
    pthread_mutex_unlock(&(pool->thread_counter));

    /*任务数大于最小线程池个数并且存活的线程数少于最大线程个数时,创建新线程*/
    if (queue_size >= MIN_WAIT_TASK_NUM && live_thr_num < pool->max_thr_num) {
        pthread_mutex_lock(&(pool->lock));
        int add = 0;

        /*一次增加DEFAULT_THREAD个线程*/
        for (i = 0; i < pool->max_thr_num && add < DEFAULT_THREAD_VARY
                && pool->live_thr_num < pool->max_thr_num; i++) {
            if (pool->threads[i] == 0 || !is_thread_alive(pool->threads[i])) {
                pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);
                add++;
                pool->live_thr_num++;
            }
        }

        pthread_mutex_unlock(&(pool->lock));
    }

    /*销毁多余的空闲线程*/
    if ((busy_thr_num * 2) < live_thr_num && live_thr_num > pool->min_thr_num) {

        /*一次销毁DEFAULT_THREAD个线程*/
        pthread_mutex_lock(&(pool->lock));
        pool->wait_exit_thr_num = DEFAULT_THREAD_VARY;
        pthread_mutex_unlock(&(pool->lock));

        for (i = 0; i < DEFAULT_THREAD_VARY; i++) {
            /*通知处在空闲状态的线程*/
            pthread_cond_signal(&(pool->queue_not_empty));
        }
    }
}
  return NULL;
 }

完整线程池代码

#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include "threadpool.h"

#define DEFAULT_TIME 10                 
#define MIN_WAIT_TASK_NUM 10          
#define DEFAULT_THREAD_VARY 10         
#define true 1
#define false 0

typedef struct {
    void *(*function)(void *);        
    void *arg;                        
} threadpool_task_t;                   

struct threadpool_t {
    pthread_mutex_t lock;              
    pthread_mutex_t thread_counter;     
    pthread_cond_t queue_not_full;     
    pthread_cond_t queue_not_empty;     
    pthread_t *threads;                 
    pthread_t adjust_tid;             
    threadpool_task_t *task_queue;     
    int min_thr_num;                  
    int max_thr_num;                    
    int live_thr_num;                  
    int busy_thr_num;                  
    int wait_exit_thr_num;            
    int queue_front;                  
    int queue_rear;                     
    int queue_size;                    
    int queue_max_size;                
    int shutdown;                     
};

void *threadpool_thread(void *threadpool);
void *adjust_thread(void *threadpool);
int is_thread_alive(pthread_t tid);
int threadpool_free(threadpool_t *pool);

threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size)
{
    int i;
    threadpool_t *pool = NULL;
    do{
        if((pool = (threadpool_t *)malloc(sizeof(threadpool_t))) == NULL) {
            printf("malloc threadpool fail");
            break;        
        }

        pool->min_thr_num = min_thr_num;
        pool->max_thr_num = max_thr_num;
        pool->busy_thr_num = 0;
        pool->live_thr_num = min_thr_num;
        pool->queue_size = 0;
        pool->queue_max_size = queue_max_size;
        pool->queue_front = 0;
        pool->queue_rear = 0;
        pool->shutdown = false;

        pool->threads = (pthread_t *)malloc(sizeof(pthread_t)*max_thr_num);
        if (pool->threads == NULL) {
            printf("malloc threads fail");
            break;
        }
        memset(pool->threads, 0, sizeof(pthread_t)*max_thr_num);

        pool->task_queue = (threadpool_task_t *)malloc(sizeof(threadpool_task_t)*queue_max_size);
        if (pool->task_queue == NULL) {
            printf("malloc task_queue fail");
            break;
        }

        if (pthread_mutex_init(&(pool->lock), NULL) != 0
                || pthread_mutex_init(&(pool->thread_counter), NULL) != 0
                || pthread_cond_init(&(pool->queue_not_empty), NULL) != 0
                || pthread_cond_init(&(pool->queue_not_full), NULL) != 0)
        {
            printf("init the lock or cond fail");
            break;
        }

        for (i = 0; i < min_thr_num; i++) {
            pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);
            printf("start thread 0x%x...\n", (unsigned int)pool->threads[i]);
        }
        pthread_create(&(pool->adjust_tid), NULL, adjust_thread, (void *)pool);
        return pool;
    } while (0);
    threadpool_free(pool);    
    return NULL;
}

int threadpool_add(threadpool_t *pool, void*(*function)(void *arg), void *arg)
{
    pthread_mutex_lock(&(pool->lock));

    while ((pool->queue_size == pool->queue_max_size) && (!pool->shutdown)) {
        pthread_cond_wait(&(pool->queue_not_full), &(pool->lock));
    }
    if (pool->shutdown) {

        pthread_mutex_unlock(&(pool->lock));
    }

    if (pool->task_queue[pool->queue_rear].arg != NULL) {
        free(pool->task_queue[pool->queue_rear].arg);
        pool->task_queue[pool->queue_rear].arg = NULL;
    }
    pool->task_queue[pool->queue_rear].function = function;
    pool->task_queue[pool->queue_rear].arg = arg;
    pool->queue_rear = (pool->queue_rear + 1)%pool->queue_max_size;
    pool->queue_size++;

    pthread_cond_signal(&(pool->queue_not_empty));
    pthread_mutex_unlock(&(pool->lock));

    return 0;
}

void *threadpool_thread(void *threadpool)
{
    threadpool_t *pool = (threadpool_t *)threadpool;
    threadpool_task_t task;
    while (true) {
        pthread_mutex_lock(&(pool->lock));
        while ((pool->queue_size == 0) && (!pool->shutdown)) {
            printf("thread 0x%x is waiting\n", (unsigned int)pthread_self());
            pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock));
            if (pool->wait_exit_thr_num > 0) {
            if (pool->live_thr_num > pool->min_thr_num) {
                    printf("thread 0x%x is exiting\n", (unsigned int)pthread_self());
                    pool->live_thr_num--;
                    pthread_mutex_unlock(&(pool->lock));
                    pthread_exit(NULL);
                }
            }
        }

        if (pool->shutdown) {
            pthread_mutex_unlock(&(pool->lock));
            printf("thread 0x%x is exiting\n", (unsigned int)pthread_self());
            pthread_exit(NULL);
        }

        task.function = pool->task_queue[pool->queue_front].function;
        task.arg = pool->task_queue[pool->queue_front].arg;
        pool->queue_front = (pool->queue_front + 1)%pool->queue_max_size;
        pool->queue_size--;

        pthread_cond_broadcast(&(pool->queue_not_full));

        pthread_mutex_unlock(&(pool->lock));


        printf("thread 0x%x start working\n", (unsigned int)pthread_self());
        pthread_mutex_lock(&(pool->thread_counter));
        pool->busy_thr_num++;                                       
        pthread_mutex_unlock(&(pool->thread_counter));
        (*(task.function))(task.arg);                               
        //task.function(task.arg);                               
        printf("thread 0x%x end working\n", (unsigned int)pthread_self());
        pthread_mutex_lock(&(pool->thread_counter));
        pool->busy_thr_num--;                                       
        pthread_mutex_unlock(&(pool->thread_counter));
    }

    pthread_exit(NULL);
    //return (NULL);
}

void *adjust_thread(void *threadpool)
{
    int i;
    threadpool_t *pool = (threadpool_t *)threadpool;
    while (!pool->shutdown) {
        sleep(DEFAULT_TIME);                                   
        pthread_mutex_lock(&(pool->lock));
        int queue_size = pool->queue_size;
        int live_thr_num = pool->live_thr_num;
        pthread_mutex_unlock(&(pool->lock));

        pthread_mutex_lock(&(pool->thread_counter));
        int busy_thr_num = pool->busy_thr_num;
        pthread_mutex_unlock(&(pool->thread_counter));
        if (queue_size >= MIN_WAIT_TASK_NUM && live_thr_num < pool->max_thr_num) {
            pthread_mutex_lock(&(pool->lock));
            int add = 0;
            for (i = 0; i < pool->max_thr_num && add < DEFAULT_THREAD_VARY
                    && pool->live_thr_num < pool->max_thr_num; i++) {
                if (pool->threads[i] == 0 || !is_thread_alive(pool->threads[i])) {
                    pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);
                    add++;
                    pool->live_thr_num++;
                }
            }

            pthread_mutex_unlock(&(pool->lock));
        }

        if ((busy_thr_num * 2) < live_thr_num && live_thr_num > pool->min_thr_num) {

            pthread_mutex_lock(&(pool->lock));
            pool->wait_exit_thr_num = DEFAULT_THREAD_VARY;
            pthread_mutex_unlock(&(pool->lock));

            for (i = 0; i < DEFAULT_THREAD_VARY; i++) {

                pthread_cond_signal(&(pool->queue_not_empty));
            }
        }
    }

    return NULL;
}

int threadpool_destroy(threadpool_t *pool)
{
    int i;
    if (pool == NULL) {
        return -1;
    }
    pool->shutdown = true;

    pthread_join(pool->adjust_tid, NULL);

    for (i = 0; i < pool->live_thr_num; i++) {
        pthread_cond_broadcast(&(pool->queue_not_empty));
        pthread_join(pool->threads[i], NULL);
    }
    threadpool_free(pool);

    return 0;
}

int threadpool_free(threadpool_t *pool)
{
    if (pool == NULL) {
        return -1;
    }

    if (pool->task_queue) {
        free(pool->task_queue);
    }
    if (pool->threads) {
        free(pool->threads);
        pthread_mutex_lock(&(pool->lock));
        pthread_mutex_destroy(&(pool->lock));
        pthread_mutex_lock(&(pool->thread_counter));
        pthread_mutex_destroy(&(pool->thread_counter));
        pthread_cond_destroy(&(pool->queue_not_empty));
        pthread_cond_destroy(&(pool->queue_not_full));
    }
    free(pool);
    pool = NULL;

    return 0;
}

int threadpool_all_threadnum(threadpool_t *pool)
{
    int all_threadnum = -1;
    pthread_mutex_lock(&(pool->lock));
    all_threadnum = pool->live_thr_num;
    pthread_mutex_unlock(&(pool->lock));
    return all_threadnum;
}

int threadpool_busy_threadnum(threadpool_t *pool)
{
    int busy_threadnum = -1;
    pthread_mutex_lock(&(pool->thread_counter));
    busy_threadnum = pool->busy_thr_num;
    pthread_mutex_unlock(&(pool->thread_counter));
    return busy_threadnum;
}

int is_thread_alive(pthread_t tid)
{
    int kill_rc = pthread_kill(tid, 0);
    if (kill_rc == ESRCH) {
        return false;
    }

    return true;
}
N32G003学习——第九章 第三节1 串口 发送 经过第九章前2节的学习,基础打下之后,开始敲代码。 阅读详情

相关推荐

在ubuntu20.04上配置VINS_Fusion(亲测有效,一应俱全)

最近在做科研训练的时候配置了HKUST-Aerial-Robotics实验室的VINS_Fusion代码项目,经历了一些编译报错的问题,在网上查找的时候博客内容良莠不齐,且实质针对性意见不多,于是在此记录下自己配置期间遇到的一些共性问题,留作自己日后参考和大家的交流学习。

wyr1849089774的博客 8267

windows线程池

#define _WIN32_DCOM #include <SDKDDKVer.h> #include <direct.h> #include <thr/threads.h> #include <stdlib.h> #include <assert.h> #include <stdio.h&gt...

weixin_30823833的博客 116

CKEditor5富文本编辑器 - 视频引入、预览及自定义toolbar

文章目录定义遇到的问题视频部分引入媒体url失败原因解决方法:自定义视频provider视频预览及页面不显示视频问题解决方案:H5 \标签如何移除toolbar中的部分插件 一个小后端很少接触前端框架,只能在知识的海洋中漂泊。。。 定义 <script src="https://cdn.ckeditor.com/ckeditor5/16.0.0/classic/ckeditor.js"&gt...

huhui806的博客 8198

C++之多线程(C++11 thread.h文件实现多线程)

转载自: http://www.cnblogs.com/haippy/p/3235560.html http://www.cnblogs.com/lidabo/p/3908705.html 与 C++11 多线程相关的头文件 C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是 ,,,和。 :该头文主要声明了两个类, std::atomic 和 std::atomic_fla

Lavi的专栏 2万+

「极简」扣子(coze)教程 | 细节决定成败!这个小功能让用户满意度飙升,讲的太细了

这一期大师兄通过向扣子(coze)应用添加提示语的方法向用户显示系统运行的状态。

u014527622的博客 2112

避开这5个坑!STC8H DMA串口通信的实战避坑指南(115200波特率实测)

本文深入解析了STC8H单片机利用DMA实现稳定全双工串口通信的实战要点。针对115200高波特率场景,详细拆解了DMA-UART架构、关键寄存器配置、时钟精度计算、缓冲区管理及中断协同等核心环节,并提供了具体的避坑指南和调试方法,帮助开发者构建高效可靠的通信链路。

melon的博客 675

关于VS2017缺少头文件的解决办法

VS2017此次更新之后,Windows SDK版本更新到10.0.15063.0,这之后我在新建项目编译程序时遇到缺少‘WinSock2.h’等头文件的提示。解决方法: 1、调出项目属性页,选择“VC++目录”。 2、“包含目录”中添加路径“C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\shared;C:\Program

qq_34362856的博客 4万+

PLC为西门子的S7-1200,舵机为 DS3218,PLC控制舵机旋转程序实现?

🏆 本文收录于《全栈Bug调优(实战版)》专栏,致力于分享我在项目实战过程中遇到的各类Bug及其原因,并提供切实有效的解决方案。无论你是初学者还是经验丰富的开发者,本文将为你指引出一条更高效的Bug修复之路,助你早日登顶,迈向财富自由的梦想🚀!同时,欢迎大家关注、收藏、订阅本专栏,更多精彩内容正在持续更新中。让我们一起进步,Up!Up!Up!    备注: 部分问题/难题源自互联网,经过精心筛选和整理,结合数位十多年大厂实战经验资深大佬经验总结所得,数条可行方案供所需之人参考。

**My Coding Family** 998

有关线程的详细介绍thread.h

https://www.cnblogs.com/renyuan/p/6613638.html

Mr.π的博客 1662

定位分析RCU stall问题

在编译内核时打开或者在启动参数中增加这样统计信息是在采样周期中收集的。其中number行分别是发生stalled的cpu上的硬中断,软中断,和上下文的切换次数cputime行的前三列分别是硬中断,软中断和任务消耗的cpu时间,单位为ms.最后一个数字是统计的周期时间(ms).因为用户态的任务通常不会引起RCU CPU stalls,所以任务通常是内核任务,这也是为什么只统计system cpu的原因.

happyAnger6的专栏 1993

让openclaw接入web端的deepseek或着qwen,使用无限token

🪟 Windows: 提供原生的 PowerShell 一键安装支持!配置过程和官方版本是相同的,唯一的区别就是再选则model时要选择带Browser字样的deepseek或者qwen。安装之前需要先清理官方版本的安装痕迹,否则openclaw版本跳转不到这个中文版本。因为此版本与官方版本存在代差,在配置飞书时可能会出现无法安装飞书的情况。剩下的配置保持和官方版本一致操作即可。选中之后需要进行一次网页端的登录。登录后会出现可选择的model。安装完成后会跳到这个中文界面。涉及到接入飞书机器人的操作。

z1872385的博客 302

线程池模型案列

线程是一种池化技术,也是线程的一种使用模式 模型 创建一大堆线程和一个安全队列 , 循环从队列中获取任务对象,获取到任务对象后,执行任务对象中的任务接口. 线程池线程的数量取决于可用的并发处理器、处理器内核、内存、网络 sockets 等的数量 由于线程池当中的线程都是采用同一个入口函数,所以入口函数当中的功能一致,怎么处理队列当中不同的任务需求? 可以将处理函数设置为函数指针,将处理任务的函数指...

身在边城 心在编程 197

华为OD机试 - 机器人活动区域(Java 双机位C卷 200分)

现有一个机器人,可放置于 M × N的网格中任意位置,每个网格包含一个非负整数编号。之后M行表示网格数值,每行N个数值(数值大小用k表示),数值间用单个空格分隔,行首行尾无多余空格。说明:图中绿色区域,相邻网格差值绝对值都小于等于1,且为最大区域,对应网格点数目为6。M、N、k均为整数,且1

学Java,找哪吒 916

多线程及并发面试基础(8)——线程池原理及运用

接上一节讲的阻塞队列的生产者消费问题之后,接下来将就阻塞队列的另外一个使用案列——线程池原理以及使用。 1、为什么要使用线程池 在我们实际的生产中,线程池的使用频率及高。那么我们在回顾一下为什么要使用线程池呢? 线程池做的工作主要是控制运行的线程的数量,处理过程中将任务加入队列,然后在线程创建后启动这些任务,如果先生超过了最大数量,超出的数量的线程排队等候,等其他线程执行完毕,再从队列中取出任...

u013025649的专栏 332

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

快速 Get 面试题中:线程池七个参数和工作原理问题,理解万岁

这次用一个生活案例来让你快速的 get 到线程池的工作原理和七个参数的作用。 最近在复习面试题,巩固一下自己。学完看看面试题,可以很有效的知道的不足。也是为以后做准备。 你好,我是博主宁在春,希望文章能够让你有所收获,也让我们也一起努力!!! 本文主要针对线程池的七个参数及工作原理做讲解。 阅读完本文能够通过自己的语言简单阐述线程池的工作原理和画出原理图。 一、面试题 在看很多Java面试题相关的文章或者博客中,对于线程池都会有这么几个常见连环问题。 ????‍????面试官: 平时工作中使用到线程了吗

北 704

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

JUC-02 (线程池)

阻塞队列是一个队列,在数据结构中起的作用如下图:当队列是空的,从队列中获取元素的操作将会被阻塞。当队列是满的,从队列中添加元素的操作将会被阻塞。试图从空的队列中获取元素的线程将会被阻塞,直到其他线程往空的队列插入新的元素。试图向已满的队列中添加新元素的线程将会被阻塞,直到其他线程从队列中移除一个或多个元素或者完全清空,使队列变得空闲起来并后续新增。在多线程领域:所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会自动被唤起。为什么需要?

338

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Java并发计算判断线程池中的线程是否全部执行完毕

目录 1 java多线程的使用 2 shutdown和shutdownNow区别源码解析 2.1 shutdown案例 2.2 shutdownNow案例 2.3 源码解读 2.4 shutdown和shutdownNow总结 3 判断线程池中的线程是否全部执行完毕 3.1 方式一:调用ExecutorService 中的isTerminated方法 3.2 方式二:调用ExecutorService 中的awaitTermination()方法,等待子线程结束 3.3 方式三:闭锁CountDownLat

赵广陆 1355

2020.8.25线程池、定时器、三个设计模式

01_线程池 概述:程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。 线程池的特点:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。 线程池的方法 public static ExecutorService newCachedThreadPool(): 根据任务的数量来创建线程对应的线程个数 public static Execu

weixin_46669997的博客 285

《大型网站技术架构-核心原理和案列分析》读书笔记

今天花了一天的时间看完《大型网站技术架构-核心原理和案列分析》,看到一些内容有点收获,就记录下来, 好的设计绝对不是模仿、不是生搬硬套某个模式,而是在对问题深刻理解之上的创造和创新,即使是“微创新”,也是让人耳目一新的似曾相识。山寨与创新的最大区别不在于是否抄袭、是否模仿,而在于对问题和需求是否真正理解和把握。 业务驱动技术,还是技术驱动业务? 分层:应用层(MVC)、服务层、数据...

497

使用Executors 和ThreadPoolExecutor的线程池案例

  一个线程池管理工作线程池,它包含一个队列,使任务等待被执行。 一个线程池管理的可运行线程和辅助线程集合执行运行队列中的.     更多:http://mjava.org/1417.shtml ...

xx521 161

Spark版本定制第5天:案列解析Spark Streaming运行源码

本期内容: 1在线动态计算分类最热门商品案例回顾与演示 2基于案例贯通Spark Streaming的运行源码   一切不能进行实时流处理的数据都是无效的数据。在流处理时代,SparkStreaming有着强大吸引力,而且发展前景广阔,加之Spark的生态系统,Streaming可以方便调用其他的诸如SQL,MLlib等强大框架,它必将一统天下。   Spark Stream...

banzhuangou9123的博客 226

Android中HandlerThread介绍与使用案列

HandlerThread 产生背景 1、开启Thread子线程进行耗时操作 2、多次创建和销毁线程是很耗资源的 HandlerThread是什么 是handler+thread+looper结合,是一个thread内部有looper 特点: - 本质上是一个线程类,继承了thread, - 其内部有自己的Looper对象,可以进行looper循环, - 通过获取hand...

MG_ZXC的专栏 649

线程池简要学习[转]

第一个教学案列 第二个教学案列 转载于:https://www.cnblogs.com/flyant/p/4555838.html

weixin_30301449的博客 59

SpringBoot中@EnableAsync和@Async简介

SpringBoot中@EnableAsync和@Async简介0 同步和异步的执行说明1 案例一:2 案例二:3 案例三:1 @EnableAsync和@Async分析1@EnableAsync源码说明1 注解的作用2 配置使用方式3 使用@Async注解, 使方法加入线程池中运行4 Spring默认会搜索一个相关的线程池5 自定义所有的配置6 关于依赖和延迟加载7 示例代码8 方法说明9 导入的AsyncConfigurationSelector类2@Async 源码说明1 注解的作用2 执行运行被注

ABestRookie的博客 1186

手把手教你如何拿捏多线程编程四大案例

看了你也能轻松拿捏多线程编程四大案例:线程安全的单例模式,阻塞队列,定时器,线程池,一文概括所有知识点,看了就会,建议收藏

Biteht的博客 1377

JavaEE->多线程3

DataSource数据源, 一开始初始化了很多个数据库连接, 当需要用连接的时候从池子中获取一个连接, 用完了还给池子,并不真正的销毁。平时业务程序很难应对流量暴增的情况,正常的流量可以满足,大流量的时,程序会申请很多线程,各种资源,最终服务器资源耗尽,被打爆。线程池中的县城不停的扫描保存任务的集合, 当有任务的时候执行任务, 没有任务的时候阻塞等待, 但不是正真的销毁线程。cpu调度的过程中可能会产生执行顺序的问题,或当一个线程执行到一半的时间被调度走的现象。

2401_85234841的博客 820
上一篇: Red Hat Enterprise下安装docker
下一篇: select、poll、epoll用法区别与联系
The_Web3_社区
博客等级 码龄10年 388粉丝 154原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

The_Web3_社区

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值