JUC并发编程学习(十 一)-ThreadPoolExecutor线程池的学习

简介: JUC并发编程学习(十 一)-ThreadPoolExecutor线程池的学习

线程池的核心知识就是:三大方法、7个参数、拒绝策略、优化配置

线程池原理

程序运行的本质是,占用系统资源,CPU/磁盘网络使用。我们希望可以高效的使用资源!池化技术就是不断的演进出来的。

  • 池化技术
    简单的说,池化技术就是提前准备一些资源,以供使用。
    线程的创建和销毁,以及数据库的连接断开都十分浪费资源。

只有是“池”,就会设计到两个常量:

  • minSize:最小容量,核心池子的大小
  • maxSize最大容量
    这些都是为了弹性访问,保证系统运行的效率。

举一个常见的例子。去银行取钱,一般来说银行会固定开放2个窗口供人办理业务。还有3个业务窗口,只有等到高峰期才会开放使用。银行里提供了一个等待区(候客厅)有3个位置。当你去办理业务时,前面有人正办理,那你就需要坐在等待区,等待传唤。

20200401134307494.png

正常情况下,core大小:2

queue大小:3

maxSize: 5

最可以存在人数:maxSize+queue =8人

为什么要使用线程池

  1. 提高程序执行效率
  2. 控制线程的数量,防止程序崩溃

为了减少创建和销毁线程的次数,让每个线程可以多次使用,可根据系统情况调整执行的线程数量,防止消耗过多内存,所以我们可以使用线程池.

Executor 介绍

java.util.concurrent.Executor: 大部分线程池相关的接口都是实现这个接口的。

public interface Executor {
    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

它的子接口和实现的类如下:

20200401134307494.png

Executor接口的关系图例(绿色实线箭头是继承,虚线是接口实现)

20200401134307494.png

三大方法

数组有工具类Arrays,集合有工具类Collections,线程池同样有工具类Executors。利用线程池工具类Executors就可以来创建线程池。


创建线程池的三大方法


ExecutorService threadpool1 = Executors.newFixedThreadPool(5); // 固定线程池大小

ExecutorService threadpool2 = Executors.newCachedThreadPool(); //可以弹性伸缩的线程池,遇强则强

ExecutorService threadpool3 = Executors.newSingleThreadExecutor(); // 只有一个

Executors.newFixedThreadPool(n)的使用

package com.jp.executorDemo;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * @className:
 * @PackageName: com.jp.executorDemo
 * @author: youjp
 * @create: 2020-05-29 16:12
 * @description:    TODO:线程池的创建使用:1.创建固定大小的线程池,超过线程池大小部分,将拒绝
 * @Version: 1.0
 */
public class ExecutorsDemo1 {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService threadPool= Executors.newFixedThreadPool(5); //固定大小,可自行设置
        try {
            for (int i = 0; i <10 ; i++) {
                //2.使用线程池来执行线程
                threadPool.execute(()->{
                    System.out.println("线程:"+Thread.currentThread().getName()+"执行任务");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //3.关闭线程池
            threadPool.shutdown();
         }
    }
}

创建了容量大小为5的线程池,遍历10次去执行线程任务。会发现从始到终只有5个线程交替执行任务

20200401134307494.png

Executors.newCachedThreadPool()的使用

这种线程池遇强则强,会弹性扩张,在实际的工作开发中不建议使用。

package com.jp.executorDemo;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * @className:
 * @PackageName: com.jp.executorDemo
 * @author: youjp
 * @create: 2020-05-29 16:12
 * @description:    TODO:线程池的创建使用:2.创建弹性的线程池,能自动扩张
 * @Version: 1.0
 */
public class ExecutorsDemo1 {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService threadPool= Executors.newCachedThreadPool();//弹性线程池,能自动扩张
        try {
            for (int i = 0; i <10 ; i++) {
                //2.使用线程池来执行线程
                threadPool.execute(()->{
                    System.out.println("线程:"+Thread.currentThread().getName()+"执行任务");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //3.关闭线程池
            threadPool.shutdown();
        }
    }
}

有10个线程在执行任务,运行效果如下:

20200401134307494.png

Executors.newSingleThreadExecutor()的使用

package com.jp.executorDemo;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * @className:
 * @PackageName: com.jp.executorDemo
 * @author: youjp
 * @create: 2020-05-29 16:12
 * @description:    TODO:线程池的创建使用:3.创建单线程池,只有一个线程
 * @Version: 1.0
 */
public class ExecutorsDemo1 {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService threadPool= Executors.newSingleThreadExecutor();//单线程池
        try {
            for (int i = 0; i <10 ; i++) {
                //2.使用线程池来执行线程
                threadPool.execute(()->{
                    System.out.println("线程:"+Thread.currentThread().getName()+"执行任务");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //3.关闭线程池
            threadPool.shutdown();
        }
    }
}

只有一个线程在执行任务:

20200401134307494.png

在实际的工作环境中,上述的几种线程池创建方法都有很大的问题。禁止使用Executors去创建线程池。。我们要使用ThreadPoolExecutor 根据实际业务需要去自定义创建线程池。

阿里巴巴开发文档有这样写到

20200401134307494.png

使用Executors创建的线程池容易发生OOM(内存用尽). 因为它允许的其你去队列大小是integer最大值。

ThreadPoolExecutor 七大参数

在讲 ThreadPoolExecutor 7大参数之前,我们先来分析一下Executors的三大方法创建线程池的底层代码

//固定线程池大小
  public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    //创建弹性线程池
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    //创建单线程池
      public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

可以发现他们三个方法底层使用的都是去实例化一个ThreadPoolExecutor对象,设置了7个参数,这就是线程池创建的核心

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.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

7个参数

int corePoolSize, // 核心池子的大小

int maximumPoolSize, // 池子的最大大小

long keepAliveTime, // 空闲线程的保留时间,即在这个时间过后回收空闲的线程

TimeUnit unit, // 时间单位

BlockingQueue workQueue, // 队列

ThreadFactory threadFactory, // 线程工厂,不修改!用来创建线程

RejectedExecutionHandler handler // 拒绝策略

既然了解到了线程池创建的核心,那么我们就使用这个方法去实现之前银行排队办理业务的案例。

20200401134307494.png

总共8人来办理业务,日常只开启2个工作台,有3个队列位置,还有3个工作台只有等队列满了,才会开放。

package com.jp.executorDemo;
import java.util.concurrent.*;
/**
 * @className:
 * @PackageName: com.jp.executorDemo
 * @author: youjp
 * @create: 2020-05-29 16:12
 * @description 描述:线程池7大参数的使用
 * 1、只有队列满了,就会触发最大线程池,否则永远都只是corePoolSize个线程在运行,所以,队列大小一定要根据业务情况进行设置;
 * 2、当请求线程超过线程池(maximumPoolSize + workQueue),就会触发拒绝策略,至于怎么拒绝,与拒绝策略RejectedExecutionHandler有关。
 */
public class ExecutorsDemo2 {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2, // 核心池子的大小,代表核心的2个工作台
                5, // 线程池最大大小5,代表最大可开启的工作台
                2L,  // 空闲线程的保留时间
                TimeUnit.SECONDS, // 超时回收空闲的线程
                new LinkedBlockingDeque<>(3), // *根据业务设置队列大小,队列大小一定要设置*
                Executors.defaultThreadFactory(), // 不用变
                new ThreadPoolExecutor.AbortPolicy () //拒绝策略,这里使用的是默认的测了:队列满了,就丢弃任务抛出异常!
        );
        try {
            // 队列  RejectedExecutionException 拒绝策略
            for (int i = 1; i <= 8; i++) { //8个人
                // 默认在处理
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" running....");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

因为办理业务是8人,核心工作台为2个,队列只有3个位置,队列已经排满,所以会触发最多线程池,开启5个工作台。

20200401134307494.png

那如果共有9个人来办理业务,而我们设置最多只能存8人,会出现怎么样的结果呢?

20200401134307494.png

只要超过线程池大小就会触发拒绝策略

四种拒绝策略

AbortPolicy (默认的:队列满了,就丢弃任务抛出异常!);

CallerRunsPolicy(哪来的回哪去? 谁叫你来的,你就去哪里处理);

DiscardOldestPolicy (尝试将最早进入队列的任务删除,尝试加入新任务);

DiscardPolicy (队列满了任务也会丢弃,不抛出异常)。

AbortPolicy

使用该策略,当请求线程超过线程池(maximumPoolSize + workQueue)就会丢弃任务抛出异常

package com.jp.executorDemo;
import java.util.concurrent.*;
/**
 * @className:
 * @PackageName: com.jp.executorDemo
 * @author: youjp
 * @create: 2020-05-29 16:12
 * @description 描述:线程池7大参数的使用
 * 1、队列满了,就会触发最大线程池,否则永远都只是corePoolSize个线程在运行,所以,队列大小一定要根据业务情况进行设置;
 * 2、当请求线程超过线程池(maximumPoolSize + workQueue),就会触发拒绝策略,至于怎么拒绝,与拒绝策略RejectedExecutionHandler有关。
 */
public class ExecutorsDemo2 {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2, // 核心池子的大小
                5, // 线程池最大大小5
                2L,  // 空闲线程的保留时间
                TimeUnit.SECONDS, // 超时回收空闲的线程
                new LinkedBlockingDeque<>(3), // *根据业务设置队列大小,队列大小一定要设置*
                Executors.defaultThreadFactory(), // 不用变
                new ThreadPoolExecutor.AbortPolicy () //拒绝策略
        );
        try {
            // 队列  RejectedExecutionException 拒绝策略
            for (int i = 1; i <= 9; i++) { // 9个人
                // 默认在处理
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" running....");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

我们把人数设置为9,在执行测试

20200401134307494.png

CallerRunsPolicy

使用该策略,当请求线程超过线程池(maximumPoolSize + workQueue)就会哪里的会哪去执行。

package com.jp.executorDemo;
import java.util.concurrent.*;
/**
 * @className:
 * @PackageName: com.jp.executorDemo
 * @author: youjp
 * @create: 2020-05-29 16:12
 * @description 描述:线程池7大参数的使用
 * 1、队列满了,就会触发最大线程池,否则永远都只是corePoolSize个线程在运行,所以,队列大小一定要根据业务情况进行设置;
 * 2、当请求线程超过线程池(maximumPoolSize + workQueue),就会触发拒绝策略,至于怎么拒绝,与拒绝策略RejectedExecutionHandler有关。
 */
public class ExecutorsDemo2 {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2, // 核心池子的大小
                5, // 线程池最大大小5
                2L,  // 空闲线程的保留时间
                TimeUnit.SECONDS, // 超时回收空闲的线程
                new LinkedBlockingDeque<>(3), // *根据业务设置队列大小,队列大小一定要设置*
                Executors.defaultThreadFactory(), // 不用变
                new ThreadPoolExecutor.CallerRunsPolicy () //拒绝策略
        );
        try {
            // 队列  RejectedExecutionException 拒绝策略
            for (int i = 1; i <= 9; i++) { // 9个人
                // 默认在处理
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" running....");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

执行结果

20200401134307494.png

DiscardOldestPolicy

使用该策略,当请求线程超过线程池(maximumPoolSize + workQueue)就会尝试将最早进入队列的任务删除,尝试加入新任务.

package com.jp.executorDemo;
import java.util.concurrent.*;
/**
 * @className:
 * @PackageName: com.jp.executorDemo
 * @author: youjp
 * @create: 2020-05-29 16:12
 * @description 描述:线程池7大参数的使用
 * 1、队列满了,就会触发最大线程池,否则永远都只是corePoolSize个线程在运行,所以,队列大小一定要根据业务情况进行设置;
 * 2、当请求线程超过线程池(maximumPoolSize + workQueue),就会触发拒绝策略,至于怎么拒绝,与拒绝策略RejectedExecutionHandler有关。
 */
public class ExecutorsDemo2 {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2, // 核心池子的大小
                5, // 线程池最大大小5
                2L,  // 空闲线程的保留时间
                TimeUnit.SECONDS, // 超时回收空闲的线程
                new LinkedBlockingDeque<>(3), // *根据业务设置队列大小,队列大小一定要设置*
                Executors.defaultThreadFactory(), // 不用变
                new ThreadPoolExecutor.DiscardOldestPolicy   () //拒绝策略
        );
        try {
            // 队列  RejectedExecutionException 拒绝策略
            for (int i = 1; i <=15; i++) { // 15个人
                // 默认在处理
                final int temp=i;
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" running...."+temp);
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

执行结果

20200401134307494.png

DiscardPolicy

使用该策略,当请求线程超过线程池(maximumPoolSize + workQueue)队列满了,后面的任务便会丢弃,不抛出异常

package com.jp.executorDemo;
import java.util.concurrent.*;
/**
 * @className:
 * @PackageName: com.jp.executorDemo
 * @author: youjp
 * @create: 2020-05-29 16:12
 * @description 描述:线程池7大参数的使用
 * 1、队列满了,就会触发最大线程池,否则永远都只是corePoolSize个线程在运行,所以,队列大小一定要根据业务情况进行设置;
 * 2、当请求线程超过线程池(maximumPoolSize + workQueue),就会触发拒绝策略,至于怎么拒绝,与拒绝策略RejectedExecutionHandler有关。
 */
public class ExecutorsDemo2 {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2, // 核心池子的大小
                5, // 线程池最大大小5
                2L,  // 空闲线程的保留时间
                TimeUnit.SECONDS, // 超时回收空闲的线程
                new LinkedBlockingDeque<>(3), // *根据业务设置队列大小,队列大小一定要设置*
                Executors.defaultThreadFactory(), // 不用变
                new ThreadPoolExecutor.DiscardPolicy   () //拒绝策略
        );
        try {
            // 队列  RejectedExecutionException 拒绝策略
            for (int i = 1; i <=15; i++) { // 15个人
                // 默认在处理
                final int temp=i;
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" running...."+temp);
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

20200401134307494.png

线程池实现原理

20200401134307494.png

提交一个任务到线程池中,线程池的处理流程如下:


1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。


2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。


3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

优化配置

在工作中,我们应该如何合理的设置线程池的参数呢?通常我们会从2个方面去考虑

  • CPU 密集型
  • IO 密集型

CPU密集型就是根据最大能支持多少个线程同时跑,一般将线程池的maximumPoolSize(最大线程池) 参数设置与CPU处理器一样大就可以了。可以通过如下方法获取到服务器运行环境的CPU个数:

Runtime.getRuntime.availableProcessors();   //获取到所处运行环境的CPU个数

完整代码

package com.jp.executorDemo;
import java.util.concurrent.*;
/**
 * @className:
 * @PackageName: com.jp.executorDemo
 * @author: youjp
 * @create: 2020-05-29 16:12
 * @description 描述:线程池7大参数的使用
 * 1、队列满了,就会触发最大线程池,否则永远都只是corePoolSize个线程在运行,所以,队列大小一定要根据业务情况进行设置;
 * 2、当请求线程超过线程池(maximumPoolSize + workQueue),就会触发拒绝策略,至于怎么拒绝,与拒绝策略RejectedExecutionHandler有关。
 */
public class ExecutorsDemo2 {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService threadPool = new ThreadPoolExecutor(
                2, // 核心池子的大小
                Runtime.getRuntime().availableProcessors(), // 线程池最大数
                2L,  // 空闲线程的保留时间
                TimeUnit.SECONDS, // 超时回收空闲的线程
                new LinkedBlockingDeque<>(3), // *根据业务设置队列大小,队列大小一定要设置*
                Executors.defaultThreadFactory(), // 不用变
                new ThreadPoolExecutor.DiscardOldestPolicy   () //拒绝策略
        );
        try {
            // 队列  RejectedExecutionException 拒绝策略
            for (int i = 1; i <=15; i++) { // 15个人
                // 默认在处理
                final int temp=i;
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" running...."+temp);
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

IO 密集型从磁盘读写、 一个线程在IO操作的时候、另外一个线程在CPU中跑,造成CPU空闲。最大线程数应该设置为 IO任务数! 对于大文件的读写非常耗时,我们应该用单独的线程让他慢慢跑。

相关文章
|
5天前
|
安全 Java 程序员
面试直击:并发编程三要素+线程安全全攻略!
并发编程三要素为原子性、可见性和有序性,确保多线程操作的一致性和安全性。Java 中通过 `synchronized`、`Lock`、`volatile`、原子类和线程安全集合等机制保障线程安全。掌握这些概念和工具,能有效解决并发问题,编写高效稳定的多线程程序。
42 11
|
2月前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
230 6
|
2月前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
2月前
|
设计模式 安全 Java
Java 多线程并发编程
Java多线程并发编程是指在Java程序中使用多个线程同时执行,以提高程序的运行效率和响应速度。通过合理管理和调度线程,可以充分利用多核处理器资源,实现高效的任务处理。本内容将介绍Java多线程的基础概念、实现方式及常见问题解决方法。
137 0
|
3月前
|
数据挖掘 程序员 调度
探索Python的并发编程:线程与进程的实战应用
【10月更文挑战第4天】 本文深入探讨了Python中实现并发编程的两种主要方式——线程和进程,通过对比分析它们的特点、适用场景以及在实际编程中的应用,为读者提供清晰的指导。同时,文章还介绍了一些高级并发模型如协程,并给出了性能优化的建议。
50 3
|
3月前
|
Java C++
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
45 0
|
4月前
|
负载均衡 Java 调度
探索Python的并发编程:线程与进程的比较与应用
本文旨在深入探讨Python中的并发编程,重点比较线程与进程的异同、适用场景及实现方法。通过分析GIL对线程并发的影响,以及进程间通信的成本,我们将揭示何时选择线程或进程更为合理。同时,文章将提供实用的代码示例,帮助读者更好地理解并运用这些概念,以提升多任务处理的效率和性能。
75 3
|
4月前
|
并行计算 API 调度
探索Python中的并发编程:线程与进程的对比分析
【9月更文挑战第21天】本文深入探讨了Python中并发编程的核心概念,通过直观的代码示例和清晰的逻辑推理,引导读者理解线程与进程在解决并发问题时的不同应用场景。我们将从基础理论出发,逐步过渡到实际案例分析,旨在揭示Python并发模型的内在机制,并比较它们在执行效率、资源占用和适用场景方面的差异。文章不仅适合初学者构建并发编程的基础认识,同时也为有经验的开发者提供深度思考的视角。
|
26天前
|
NoSQL Redis
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
56 1
|
3月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
71 1