java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java线程池

Java并发编程之线程池实现原理详解

作者:越走越远的风

池化思想是一种空间换时间的思想,期望使用预先创建好的对象来减少频繁创建对象的性能开销,java中有多种池化思想的应用,例如:数据库连接池、线程池等,下面就来具体讲讲

前言

池化思想是一种空间换时间的思想,期望使用预先创建好的对象来减少频繁创建对象的性能开销,同时还可以对对象进行统一管理,减少对象使用成本。

java中有多种池化思想的应用,例如:数据库连接池、线程池、字符串常量池等。

为什么使用线程池

频繁的开启线程或者停止线程,线程需要重新被cpu从就绪到运行状态调度,需要发生cpu的上下文切换,效率非常低。

线程池作用

ThreadPoolExecutor参数

当线程数小于核心线程数时,创建线程。

当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。

当线程数大于等于核心线程数,且任务队列已满时:

拒绝策略

当线程池中的线程数量达到最大值或者任务队列已满时,如果再有新的任务提交给线程池,线程池会拒绝接受新的任务。这时,线程池会采用一定的拒绝策略来处理这些被拒绝的任务。

Java中提供了四种拒绝策略:

也可以自定义拒绝策略,实现RejectedExecutionHandler接口即可。

建议自定义实现拒绝策略,将任务持久化到db,后期在手动补偿。

线程池的创建方式

Executors为我们提供了四种新建线程池的方式:

newCachedThreadPool()可缓存线程池

public static ExecutorService newCachedThreadPool() {  
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,  
                                    60L, TimeUnit.SECONDS,  
                                    new SynchronousQueue<Runnable>());  
}

线程池是创建一个核心线程数为0,最大线程为Inter.MAX_VALUE的线程池,线程池数量不确定,有空闲线程则优先使用,没用则创建新的线程处理任务,处理完放入线程池。

newFixedThreadPool(): 可定长度,限制最大线程数

public static ExecutorService newFixedThreadPool(int nThreads) {  
    return new ThreadPoolExecutor(nThreads, nThreads,  
                                    0L, TimeUnit.MILLISECONDS,  
                                    new LinkedBlockingQueue<Runnable>());  
}

创建一个核心线程数跟最大线程数相同的线程池,线程池数量大小不变,如果有任务放入队列,等待空闲线程。

newScheduledThreadPool(): 可定时线程池\

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {  
    return new ScheduledThreadPoolExecutor(corePoolSize);  
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {  
    return new ScheduledThreadPoolExecutor(corePoolSize);  
}
public ScheduledThreadPoolExecutor(int corePoolSize) {  
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,  
        new DelayedWorkQueue());  
}

创建一个没有最大线程数限制的可以定时执行线程池,还有创建一个只有单个线程的可以定时执行线程池(Executors.newSingleThreadScheduledExecutor())

newSingleThreadExecutor(): 单线程 线程池

public static ExecutorService newSingleThreadExecutor() {  
    return new FinalizableDelegatedExecutorService  
        (new ThreadPoolExecutor(1, 1,  
                                0L, TimeUnit.MILLISECONDS,  
                                new LinkedBlockingQueue<Runnable>()));  
}

池里只有一个线程

这四种底层都是基于ThreadPoolExecutor构造函数封装,且都采用的无界队列,使用时需注意防止内存溢出。

自定义线程名称

可以通过自定义ThreadFactory来为线程池中的线程指定名称。

ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("custom-thread-%d").build();

线程池的五种状态

        // runState is stored in the high-order bits
        private static final int RUNNING    = -1 << COUNT_BITS;
        private static final int SHUTDOWN   =  0 << COUNT_BITS;
        private static final int STOP       =  1 << COUNT_BITS;
        private static final int TIDYING    =  2 << COUNT_BITS;
        private static final int TERMINATED =  3 << COUNT_BITS;

线程数设置

合理地设置核心线程数和最大线程数可以优化线程池的性能和响应时间。下面是一些设置建议:

具体的设置需要根据实际情况来考虑,如果线程池主要执行的是I/O密集型任务,可以适当增加核心线程数和最大线程数,以充分利用系统资源。如果线程池主要执行的是CPU密集型任务,则需要根据系统的CPU核心数来设置核心线程数和最大线程数,避免过度消耗CPU资源。

springboot集成线程池

package com.fandf.common.config;  
import com.fandf.common.utils.CustomThreadPoolTaskExecutor;  
import lombok.Getter;  
import lombok.Setter;  
import org.springframework.beans.factory.annotation.Value;  
import org.springframework.context.annotation.Bean;  
import org.springframework.core.task.TaskExecutor;  
import org.springframework.scheduling.annotation.EnableAsync;  
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;  
import java.util.concurrent.ThreadPoolExecutor;  
/**  
* @author fandongfeng   
*/  
@EnableAsync(proxyTargetClass = true) 
@Configuration
public class DefaultAsycTaskConfig {  
    /**  
    * 线程池维护线程的最小数量.  
    */  
    @Value("${asyc-task.corePoolSize:10}")  
    private int corePoolSize;  
    /**  
    * 线程池维护线程的最大数量  
    */  
    @Value("${asyc-task.maxPoolSize:200}")  
    private int maxPoolSize;  
    /**  
    * 队列最大长度  
    */  
    @Value("${asyc-task.queueCapacity:10000}")  
    private int queueCapacity;  
    /**  
    * 线程池前缀  
    */  
    @Value("${asyc-task.threadNamePrefix:FdfExecutor-}")  
    private String threadNamePrefix;  
    @Bean  
    public TaskExecutor taskExecutor() {  
        ThreadPoolTaskExecutor executor = new CustomThreadPoolTaskExecutor();  
        executor.setCorePoolSize(corePoolSize);  
        executor.setMaxPoolSize(maxPoolSize);  
        executor.setQueueCapacity(queueCapacity);  
        executor.setThreadNamePrefix(threadNamePrefix);  
        /*  
        rejection-policy:当pool已经达到max size的时候,如何处理新任务  
        CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行  
        */  
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());  
        executor.initialize();  
        return executor;  
    }  
}

使用

@Service
public class MyService {
    @Async("taskExecutor")
    public void doSomething() {
        // 异步执行的任务
    }
}

到此这篇关于Java并发编程之线程池实现原理详解的文章就介绍到这了,更多相关Java线程池内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文