Java多线程——线程池

为什么需要线程池?
在实际使用中,线程是很占用系统资源的,如果对线程管理不善很容易导致系统问题.因此,在大多数并发框架中都会使用线程池来管理线程,使用线程池管理线程主要有如下好处:

  1. 使用线程池可以重复利用已有的线程继续执行任务,避免线程在创建和销毁时造成消耗
  2. 由于没有线程创建和销毁时的消耗,可以提高系统响应速度
  3. 通过线程可以对线程进行合理的管理,根据系统的承受能力调整可运行线程数量的大小等

下面是线程池的工作原理图
在这里插入图片描述

线程池的分类

一、ThreadPoolExecutor

子类说明
newCachedThreadPool创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的ThreadFactory创建新线程.特征:(1)线程池中数量没有固定,可达到最大值(Interger.MAX_VALUE) . (2)线程池中的线程可进行缓存重复利用和回收(回收默认时间为1分钟) (3)当线程池中没有可用线程,会重新创建一个新线程
newFixedThreadPool创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程,在任意点,在大多数nThread线程会处于处理任务的活动状态,如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待,如果在关闭前的执行期间由于失败而导致线程终止,那么一个新线程将代替它执行后续的任务(如果需要).在某个线程被显式地关闭之前,池中的线程将一直存在. 特征:(1)线程池中的线程处于一定的量,可以很好的控制线程的并发量 (2)线程可以重复被使用,在显式关闭之前,都将一直存在 (3)超出一定量的线程被提交时,需在队列中等待
newSingleThreadPool创建一个使用单个线程的Executor,以无界队列的方式来运行该线程.(注意:如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,一个新线程将代替它执行后续任务).可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的,与其他有效的newFixedThreadPool不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程. 特征: 线程池中最多执行1个线程,之后提交的线程活动会排在队列中以此执行

1.newCachedThreadPool

public class CacheThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i =0;i<10;i++){
            executorService.execute(new Task());
        }
        executorService.shutdown();
    }
}

2.newFixedThreadPool

public class FixeThreadDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0;i<10;i++){
            executorService.execute(new Task());
        }
        executorService.shutdown();
    }
}

3.newSingleThreadPool

public class SingleThreadExecutor {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i =0;i<10;i++){
            executorService.execute(new Task());
        }
        executorService.shutdown();
    }
}

二、ScheduledThreadPoolExecutor

子类说明
newSingleThreadScheduledExecutor创建一个单线程执行程序,它可安排在给定程序延迟后运行命令或者定期地执行. 特征:(1)线程池中最多执行1个线程,之后提交的线程活动将会安排在队列中以此执行. (2)可定时或者延迟执行线程活动
newScheduledThreadPool创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行. 特征:(1)线程池中具有给定数量的线程,即便是空线程也将保留. (2)可定时或者延迟执行线程活动

1.newScheduledThreadPool
类型1:

public class ScheduledThreadPoolDemo {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        System.out.println(System.currentTimeMillis());
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("延迟三秒执行。。。");
                System.out.println(System.currentTimeMillis());
            }
        },3, TimeUnit.SECONDS);
        scheduledExecutorService.shutdown();
    }
}

类型2:

public class ScheduledThreadPoolDemo2 {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        System.out.println(System.currentTimeMillis());
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("延迟1秒执行。。。每三秒执行一次");
                System.out.println(System.currentTimeMillis());
            }
        },1,3, TimeUnit.SECONDS);
//        scheduledExecutorService.shutdown();
    }
}

三、ForkJoinPool

子类说明
newWorkStealingPool创建一个带并行级别的线程池,并行级别决定了同一时刻最多有多少个线程在执行,如不传入并行级别参数,将默认为当前系统的CPU个数

线程池的生命周期

在这里插入图片描述
线程池的生命周期一共两个状态,RUNNING运行状态和TERMINATED终止状态,但在从running状态到terminated状态的时候,中间会出现SHUTDOWN、STOP、TIDYING三种不同的过度状态
1、在调用shut down()方法时,过度状态为SHUTDOWN
2、在调用shut down now()方法时,会进入STOP状态
3、最终两种状态都会进入到TIDYING状态进行回收.SHOUTDOWN状态会将线程池中的所有工作都进行完,才会进行回收,是非暴力的;STOP状态会将正在进行中的任务强制关闭,是暴力的(不推荐).

理论解释:

  1. RUNNING: 能接受新提交的任务,并且也能处理阻塞队列中的任务
  2. SHUTDOWN: 关闭状态,不再接受新提交的任务,但却可以继续处理阻塞队列中已保存的任务
  3. STOP: 不能接受新任务,也不处理队列中的任务,会中断正在处理任务的线程
  4. TIDYING: 如果所有的任务都已终止了,workerCount(有效线程)为0,线程池进入该状态后会调用terminated()方法进入TERMINATED状态
  5. TERMINATED: 在terminated()方法执行完后进入该状态,默认terminated()方法中什么也没有做

注意:不要将线程池的生命周期和线程的生命周期搞混了,面试的时候可得听清楚了,问清楚了再回答😂

线程池的创建

public ThreadPoolExecutor(int corePoolSize,		//核心线程数
						int maximumPoolSize,	//最大线程数
						long keepAliveTime,		//存活时间
						TimeUnit unit,			//时间单位
						BlockingQueue<Runnable> workQueue,	//阻塞队列
						ThreadFactory threadFactory,		//工厂模式
						RejectedExecutionHandler handler	//饱和策略){

拒绝策略

  • ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectExecutionException异常(推荐)
  • ThreadPoolExecutor.DiscardPolicy: 也是丢弃任务,但是不抛出异常
  • ThreadPoolExecutor.DiscardOldestPolicy: 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
  • ThreadPoolExecutor.CallerRunsPolicy: 由调用线程处理该任务

executor方法执行逻辑

  • 如果当前运行的线程少于corePoolSize,则会创建新的线程来执行新的任务;
  • 如果运行的线程个数等于或者大于corePoolSize,则会将提交的任务存放到阻塞队列workQueue中;
  • 如果当前workQueue队列已满的话,则会创建新的线程来执行任务;
  • 如果线程个数已经超过了maximumPoolSize,则会使用饱和策略RejectedExecutionHandler来进行处理

Executor和Submit

submit是基于方法Executor.execute(Runnable)的延伸,通过创建并返回一个Future类对象可用于取消执行和/或等待完成

public class Task implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        return Thread.currentThread().getName()+"isRunning";
    }
}
public class Test {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i=0;i<10;i++){
            Future<?> submit = executorService.submit(new Task());
            try {
                String str = (String) submit.get();
                System.out.println(str);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        executorService.shutdown();
    }
}

线程池的关闭

关闭线程池,可以通过shutdown和shutdownNow两个方法
原理:遍历线程池中的线程,然后依次中断

  1. shutdownNow 首先将线程池的状态设置为STOP,然后尝试停止所有正在执行和未执行任务的线程,并返回等待执行任务的列表
  2. shutdown只是将线程池的状态设置为SHUTDOWN状态,然后中断所有没有正在执行任务的线程
以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值