如何解决多线程卡死问题?四招教你轻松应对!

多线程大家都用过,可以让一个程序同时执行多个任务,提高效率和性能,一个人干的慢,三个人干。但是,多线程也带来了一些问题和挑战,比如线程同步线程安全线程死锁等问题,三个人抢一碗米饭,没有个规矩肯定要打架的。

这里我介绍一种可能出现的多线程问题:如果一个线程在执行过程中一直卡住,线程不释放最终导致线程耗尽怎么办。

这是前一阶段对接外部系统时遇到的一个问题,对方提供了个SDK,我们集成后用他们的netty的方式建立连接,推送相关数据,但是呢这个推送不能阻塞业务,所以我们采用异步推送,搞了个线程池,随取随还,如图

 

后来就发现有一个现象,推着推着就不推了,卡到多线程前那里,也不进去,也不拒绝

然后我用executor.getTaskCount(), executor.getActiveCount(),executor.getCompletedTaskCount()打印日志发现活跃数没有了,并且拒绝策略是CallerRunsPolicy()(这个策略的意思:当任务添加到线程池中被拒绝时,会使用调用线程池的Thread线程对象处理被拒绝的任务,有个问题就是都没有线程对象了,自然也取不到来执行),所以看起来也不报错,像是假死,拒绝策略先不说,这里我们只处理线程耗尽的问题

我们升华一下对于这类问题我们要如何处理

问题分析

首先我们分析下为什么会出现这种情况。一个线程在执行过程中可能会遇到下面几种原因导致卡住:

  1. 线程等待某个资源或条件,但是资源或条件一直不满足,比如网络请求超时、锁竞争失败等。
  2. 线程遇到死循环或无限递归,导致程序逻辑无法继续执行。
  3. 线程遇到异常或错误,但是没有正确处理,导致程序崩溃或挂起。
  4. 如果一个线程卡住了,那么它就无法释放它占用的资源,比如内存、CPU、锁等等。这样就会影响其他线程的运行,甚至导致整个程序的性能下降或崩溃。如果我们不断地创建新的线程,而旧的线程不释放,最终就会导致线程耗尽。就会抛出OutOfMemoryError或UnableToCreateThreadException异常。

解决方案

针对上面的问题,我列了几种解决方案:

  1. 限制线程的数量。我们可以使用线程池来管理和复用线程,而不是每次都创建新的线程。这样可以避免创建过多的线程,也可以提高线程的利用率和管理性。
  2. 设置超时机制。我们可以给每个线程设置一个合理的超时时间,如果超过了这个时间,就认为该线程卡住了,并且强制中断或杀死该线程。这样可以避免某个线程无限等待或执行。
  3. 检查和优化代码逻辑。我们应该检查和测试我们的代码逻辑,避免出现死循环或无限递归等错误。如果发现有问题,我们应该及时修复和优化。
  4. 处理异常和错误。我们应该在每个线程中捕获并处理可能出现的异常和错误,并且在合适的时候释放资源和结束线程。这样可以避免程序崩溃或挂起。

不同的场景大家可以选用不同的方案,下面我针对第二种方案举个栗子,看看超时机制怎么设计,其他三种就不多说了

大家可以看到我们用了submit方法,得到一个Future,然后利用超时等待get方法来控制如果超时了TimeoutException,我们future.cancel(),这样就可以主动释放线程,不用一直阻塞了

// 创建一个线程池
ExecutorService executor = Executors.newSingleThreadExecutor();
// 提交一个任务
Future<String> future = executor.submit(new Callable<String>() {
    @Override
    public String call() throws Exception {
        // 这里是你要执行的代码,比如br.readLine()
        return br.readLine();
    }
});
// 设置一个超时时间,比如5秒
long timeout = 5;
// 尝试获取任务的结果,如果超时就抛出异常
try {
    String s = future.get(timeout, TimeUnit.SECONDS);
    // 如果没有超时,就正常处理结果
    System.out.println(s);
} catch (TimeoutException e) {
    // 如果超时,就取消任务,并且处理异常
    future.cancel(true);
    System.out.println("Time out has occurred");
}
// 关闭线程池
executor.shutdown();

 多线程是一种强大而复杂的编程技术,使用时要注意避免一些常见的问题和风险,后面会继续分享一些案例以及在在这期间用到的技术,找到每种技术合适的使用场景很重要

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我是小酒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值