关于thread:线程池-ThreadPoolExecutor-详解

一 为什么要应用线程池对于操作系统而言,创立一个线程的代价是非常低廉的, 须要给它分配内存、列入调度,同时在线程切换时要执行内存换页,清空 CPU 缓存,切换回来时还要从新从内存中读取信息,毁坏了数据的局部性。因而在并发编程中,当线程创立过多时,会影响程序性能,甚至引起程序解体。而线程池属于池化管理模式,具备以下长处: 升高资源耗费:通过反复利用已创立的线程升高线程创立和销毁造成的性能耗费。进步响应速度:当工作达到时,工作能够不须要等到线程创立就能立刻执行。进步线程的可管理性:可能对线程进行统一分配、调优和监控。 二 线程池原理详解2.1 线程池外围组成线程池蕴含 3 个外围局部: 线程汇合:外围线程和工作线程阻塞队列:用于待执行工作排队回绝策略处理器:阻塞队列满后,对工作解决进行 2.2 Execute 原理当一个新工作提交至线程池之后,线程池的解决流程如下: 首先判断以后运行的线程数量是否小于 corePoolSize。如果是,则创立一个工作线程来执行工作;如果都在执行工作,则进入步骤 2。判断 BlockingQueue 是否曾经满了,若没满,则将工作放入 BlockingQueue;若满了,则进入步骤 3。判断以后运行的总线程数量是否小于 maximumPoolSize,如果是则创立一个新的工作线程来执行工作。否则交给 RejectedExecutionHandler 来解决工作。 当 ThreadPoolExecutor 创立新线程时,通过 CAS 来更新线程池的状态 ctl。 三 线程池的应用线程池的应用次要分为以下三个步骤: 3.1 创立线程池3.1.1 自定义线程池线程池的真正实现类是 ThreadPoolExecutor,其构造方法有如下 4 种:public ThreadPoolExecutor(int corePoolSize,                          int maximumPoolSize,                          long keepAliveTime,                          TimeUnit unit,                          BlockingQueue<Runnable> workQueue) {    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,         Executors.defaultThreadFactory(), defaultHandler);} public ThreadPoolExecutor(int corePoolSize,                          int maximumPoolSize,                          long keepAliveTime,                          TimeUnit unit,                          BlockingQueue<Runnable> workQueue,                          ThreadFactory threadFactory) {    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,         threadFactory, defaultHandler);} public ThreadPoolExecutor(int corePoolSize,                          int maximumPoolSize,                          long keepAliveTime,                          TimeUnit unit,                          BlockingQueue<Runnable> workQueue,                          RejectedExecutionHandler handler) {    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,         Executors.defaultThreadFactory(), handler);} public ThreadPoolExecutor(int corePoolSize,                          int maximumPoolSize,                          long keepAliveTime,                          TimeUnit unit,                          BlockingQueue<Runnable> workQueue,                          ThreadFactory threadFactory,                          RejectedExecutionHandler handler) {    if (corePoolSize < 0 ||        maximumPoolSize <= 0 ||        maximumPoolSize < corePoolSize ||        keepAliveTime < 0)        throw new IllegalArgumentException();    if (workQueue == null || threadFactory == null || handler == null)        throw new NullPointerException();    this.corePoolSize = corePoolSize;    this.maximumPoolSize = maximumPoolSize;    this.workQueue = workQueue;    this.keepAliveTime = unit.toNanos(keepAliveTime);    this.threadFactory = threadFactory;    this.handler = handler;}复制代码上面具体来看构造函数须要传入的重点参数: ...

July 29, 2022 · 4 min · jiezi

关于thread:C线程池

title: C线程池categories: [C++]tags:[编程语言]date: 2021/06/28 <div align = 'right'>作者:hackett</div> <div align = 'right'>微信公众号:加班猿</div> C线程池1、筹备工作查看线程相干接口函数:线程创立int pthread_create(pthread_t thread, const pthread_attr_t attr,void (start_routine) (void ), void arg); 参数阐明: 1.参数thread指向寄存新创建线程的线程ID的地址 2.attr参数用于定制各种不同的线程属性,暂能够把它设置为NULL,以创立默认属性的线程。 3.start_routine是个函数指针,该函数返回类型是void,同时形式参数也是void。新创建的线程从start_routine函数的地址开始运行。该函数只有一个无类型指针参数arg.如果须要向start_routine函数传递的参数不止一个,那么须要把这些参数放到一个构造中,而后把这个构造的地址作为arg参数传入。 返回值: 线程创立胜利返回0,失败返回其余数值 线程退出void pthread_exit(void *retval); 参数阐明: retval是一个无类型指针,过程中的其余线程能够通过调用pthread_join函数拜访到这个指针。 线程期待int pthread_join(pthread_t thread, void **retval); 参数阐明: 调用这个函数的线程将始终阻塞,直到指定的线程调用pthread_exit. 如果对线程的返回值不感兴趣,能够把retval置为NULL。在这种状况下,调用pthread_join函数将期待指定的线程终止,但并不取得线程的终止状态。 线程勾销int pthread_cancel(pthread_t thread); 参数阐明: thread为线程的id 设置线程的cancle信号int pthread_setcancelstate(int state, int *oldstate) ; PTHREAD_CANCEL_ENABLE:线程可勾销。这是所有新线程的默认勾销状态,包含初始线程。线程的可勾销类型决定了可勾销线程何时响应勾销申请。 PTHREAD_CANCEL_DISABLE:线程不可勾销。如果收到一个勾销申请,它将被阻塞,直到可勾销启用。 清理线程void pthread_cleanup_push(void (*rtn)(void *), void *arg); 参数阐明: void(*rtn)(void *):线程清理函数 arg传递的参数 激活所有期待线程pthread_cond_broadcast(pthread_cond_t *cond); 查看互斥锁相干接口函数:创立互斥锁int pthread_mutex_init(pthread_mutex_t restrict mutex,const pthread_mutexattr_t restrict attr); ...

June 30, 2021 · 3 min · jiezi

关于thread:springboot中使用线程池实现异步调用

1.什么是线程池?线程池是一种多线程解决模式,解决过程中将工作增加到队列,而后在创立线程后主动启动这些工作。线程池线程都是后盾线程。每个线程都应用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中闲暇(如正在期待某个事件),则线程池将插入另一个辅助线程来使所有处理器放弃忙碌。如果所有线程池线程都始终保持忙碌,但队列中蕴含挂起的工作,则线程池将在一段时间后创立另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程能够排队,但他们要等到其余线程实现后才启动。 2.常见的线程池2.1 newCachedThreadPool创立一个可缓存线程池,如果线程池长度超过解决须要,可灵便回收闲暇线程,若无可回收,则新建线程。这种类型的线程池特点是:工作线程的创立数量简直没有限度(其实也有限度的,数目为Interger. MAX_VALUE), 这样可灵便的往线程池中增加线程。如果长时间没有往线程池中提交工作,即如果工作线程闲暇了指定的工夫(默认为1分钟),则该工作线程将主动终止。终止后,如果你又提交了新的工作,则线程池从新创立一个工作线程。在应用CachedThreadPool时,肯定要留神管制工作的数量,否则,因为大量线程同时运行,很有会造成零碎瘫痪。 2.2 newFixedThreadPool创立一个指定工作线程数量的线程池。每当提交一个工作就创立一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的工作存入到池队列中。FixedThreadPool是一个典型且优良的线程池,它具备线程池进步程序效率和节俭创立线程时所耗的开销的长处。然而,在线程池闲暇时,即线程池中没有可运行工作时,它不会开释工作线程,还会占用肯定的系统资源。 2.3 newSingleThreadExecutor创立一个单线程化的Executor,即只创立惟一的工作者线程来执行工作,它只会用惟一的工作线程来执行工作,保障所有工作依照指定程序(FIFO, LIFO, 优先级)执行。如果这个线程异样完结,会有另一个取代它,保障程序执行。单工作线程最大的特点是可保障程序地执行各个工作,并且在任意给定的工夫不会有多个线程是流动的。 2.4 newScheduleThreadPool创立一个定长的线程池,而且反对定时的以及周期性的工作执行,反对定时及周期性工作执行。 3.5 下图可见newScheduleThreadPool线程池是ThreadPoolExecutor的子类,所以本章将围绕ThreadPoolExecutor线程池去做详解。 ThreadPoolExecutor详解进入ThreadPoolExecutor类中,能够看到,创立这个线程池,有四种形式,且全是有参结构。 查看全参结构corePoolSize:外围线程池大小maximumPoolSize:容许线程池同时并行的线程数量keepAliveTime:当线程数大于内核数时,这是多余的闲暇线程将在终止之前期待新工作的最长工夫unit:TimeUnit类型,这没什么好说workQueue:在执行工作之前用于保留工作的队列,此队列将仅保留execute办法提交的Runnable工作。threadFactory:执行程序创立新线程时要应用的工厂handler:当线期待队列中的数量超过既定容量,所须要解决策略 综上所述,咱们做异步的话,不须要回绝策略,所以,咱们抉择没有回绝策略参数的构造方法去创立。 1.初始化线程池@Componentpublic class ThreadPoolStarter { @Value("${thread-pool.corePoolSize:2}") private Integer corePoolSize; @Value("${thread-pool.maxPoolSize:3}") private Integer maximumPoolSize; @Value("${thread-pool.queueSize:10}") private Integer queueSize; @Value("${thread-pool.keepAliveTime:600}") private Long keepAliveTime; private TimeUnit unit = TimeUnit.SECONDS; @Bean("workerPool") public ThreadPoolExecutor threadPool() { // 线程工厂 ThreadFactory threadFactory = new CustomizableThreadFactory("worker-pool-"); // 初始化线程池 return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, new LinkedBlockingQueue<>(queueSize), threadFactory); }}2.创立线程类实现runnable接口/** * @description * @author: yzr * @date: 2021-06-02 11:12 **/public class ThreadRunner implements Runnable { @Override public void run() { try { log.info("我要睡眠了"); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } log.info("我的业务办法"); }}3.测试,注入线程池,并把线程交由线程池去解决。@SpringBootTest(classes = CasbinApplication.class)@Slf4jpublic class SpringBootTestTest { @Autowired private ThreadPoolExecutor threadPoolExecutor; @Autowired ThreadRunner threadRunner; @Test public void test() { log.info("开始了"); threadPoolExecutor.execute(threadRunner); log.info("完结了"); }}4.执行并查看后果由此可见咱们的异步调用胜利了 ...

June 2, 2021 · 1 min · jiezi

关于thread:4种解决线程安全问题的方式

前言线程平安问题,在做高并发的零碎的时候,是程序员常常须要思考的中央。怎么无效的避免线程平安问题,保证数据的准确性?怎么正当的最大化的利用系统资源等,这些问题都须要充沛的了解并运行线程。当然对于多线程的问题在面试的时候也是呈现频率比拟高的。上面就来学习一下吧! 线程先来看看什么是过程和线程? 过程是资源(CPU、内存等)调配的根本单位,它是程序执行时的一个实例。程序运行时零碎就会创立一个过程,并为它分配资源,而后把该过程放入过程就绪队列,过程调度器选中它的时候就会为它调配CPU工夫,程序开始真正运行。就比如说,咱们开发的一个单体我的项目,运行它,就会产生一个过程。 线程是程序执行时的最小单位,它是过程的一个执行流,是CPU调度和分派的根本单位,一个过程能够由很多个线程组成,线程间共享过程的所有资源,每个线程有本人的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就容许多个线程同时运行。同样多线程也能够实现并发操作,每个申请调配一个线程来解决。在这里强调一点就是:计算机中的线程和应用程序中的线程不是同一个概念。 总之一句话形容就是:过程是资源分配的最小单位,线程是程序执行的最小单位。 什么是线程平安什么是线程平安呢?什么样的状况会造成线程平安问题呢?怎么解决线程平安呢?这些问题都是在下文中所要讲述的。 线程平安:当多个线程拜访一个对象时,如果不必思考这些线程在运行时环境下的调度和交替执行,也不须要进行额定的同步,或者在调用方进行任何其余的协调操作,调用这个对象的行为都能够取得正确的后果,那这个对象就是线程平安的。 那什么时候会造成线程平安问题呢?当多个线程同时去拜访一个对象时,就可能会呈现线程平安问题。那么怎么解决呢?请往下看! 解决线程平安在这里提供4种办法来解决线程平安问题,也是最罕用的4种办法。前提是我的项目在一个服务器中,如果是分布式我的项目可能就会用到散布锁了,这个就放到前面文章来详谈了。 讲4种办法前,还是先来理解一下乐观锁和乐观锁吧! 乐观锁,顾名思义它是乐观的。讲得艰深点就是,认为本人在应用数据的时候,肯定有别的线程来批改数据,因而在获取数据的时候先加锁,确保数据不会被线程批改。形象了解就是总感觉有刁民想害朕。 而乐观锁就比拟乐观了,认为在应用数据时,不会有别的线程来批改数据,就不会加锁,只是在更新数据的时候去判断之前有没有别的线程来更新了数据。具体用法在上面解说。 当初来看有那4种办法吧! 办法一:应用synchronized关键字,一个体现为原生语法层面的互斥锁,它是一种乐观锁,应用它的时候咱们个别须要一个监听对象 并且监听对象必须是惟一的,通常就是以后类的字节码对象。它是JVM级别的,不会造成死锁的状况。应用synchronized能够拿来润饰类,静态方法,一般办法和代码块。比方:Hashtable类就是应用synchronized来润饰办法的。put办法局部源码: public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { throw new NullPointerException(); } 而ConcurrentHashMap类中就是应用synchronized来锁代码块的。putVal办法局部源码: else { V oldVal = null; synchronized (f) { if (tabAt(tab, i) == f) { if (fh >= 0) { binCount = 1;synchronized关键字底层实现次要是通过monitorenter 与monitorexit计数 ,如果计数器不为0,阐明资源被占用,其余线程就不能拜访了,然而可重入的除外。说到这,就来讲讲什么是可重入的。这里其实就是指的可重入锁:指的是同一线程外层函数取得锁之后,内层递归函数依然有获取该锁的代码,但不受影响,执行对象中所有同步办法不必再次取得锁。防止了频繁的持有开释操作,这样既晋升了效率,又防止了死锁。 ...

November 29, 2020 · 2 min · jiezi

关于thread:第三阶段-Day20-购物车模块实现-添加拦截器-添加用户权限校检-实现订单模块

购物车删除操作=========== 1.1 页面剖析 1.2 编辑CartController `/** * 购物车删除操作 * url地址: http://www.jt.com/cart/delete/562379.html * 参数: 获取itemId * 返回值: 重定向到购物车的展示页面 */ @RequestMapping("/delete/{itemId}") public String deleteCarts(@PathVariable Long itemId){ Long userId = 7L; cartService.deleteCarts(userId,itemId); return "redirect:/cart/show.html"; }` 1.3 编辑CartService `@Override public void deleteCarts(Long userId, Long itemId) { QueryWrapper<Cart> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("user_id", userId); queryWrapper.eq("item_id", itemId); cartMapper.delete(queryWrapper); }` 京淘权限实现========== 2.1 业务需要当用户进行敏感操作时,必须要求用户先登录之后才能够拜访后端服务器. 例如京东商城…应用技术:1.AOP2.拦截器 :拦挡用户的申请 2.2 定义京淘拦截器2.2.1 SpringMVC调用原理图2.2.2 SpringMVC拦截器工作原理 2.2.3 配置拦截器`@Component //spring容器治理对象public class UserInterceptor implements HandlerInterceptor { @Autowired private JedisCluster jedisCluster; //Spring版本升级 4 必须实现所有的办法 spring 5 只须要重写指定的办法即可. /** * 需要: 拦挡/cart结尾的所有的申请进行拦挡.,并且校验用户是否登录..... * 拦截器抉择: preHandler * 如何判断用户是否登录: 1.查看cookie信息 2.查看Redis中是否有记录. * true : 申请应该放行 * false: 申请应该拦挡 则配合重定向的语法实现页面跳转到登录页面 使得程序流转起来 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //1.判断用户是否登录 查看cookie是否有值 String ticket = CookieUtil.getCookieValue(request,"JT_TICKET"); //2.校验ticket if(!StringUtils.isEmpty(ticket)){ //3.判断redis中是否有值. if(jedisCluster.exists(ticket)){ //4.动静获取json信息 String userJSON = jedisCluster.get(ticket); User user = ObjectMapperUtil.toObj(userJSON,User.class); request.setAttribute("JT_USER",user); return true; } } response.sendRedirect("/user/login.html"); return false; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //销毁数据 request.removeAttribute("JT_USER"); }}` 2.2.4 动静获取UserId ...

November 9, 2020 · 4 min · jiezi