【已解决】定时任务下,使用ftp出现线程池被打满的异常

线上环境有一个定时任务,每秒钟扫描ftp,然后取文件,结果总是莫名其妙的卡住,后来改成线程池异步执行,但是没多久就发生线程池被打满的情况。重启后没多久又又又出现这个现象🤪🤪🤪,下决心要给它解决掉!😎

问题排查:

首先使用jps命令查看服务的pid,再使用 jstack pid号 > info.txt 查看堆栈信息。
最后排查到是因为线程执行到 FTPClien.listfiles() 就会出现卡住的现象,且线程处于RUNNABLE状态。

现象总结:

ftp的连接阻塞,导致线程一直处于RUNNING状态,线程资源无法被回收,进而导致线程池需要一直创建新线程处理新的任务,直到线程池爆掉。

解决办法(2种方法):

那么问题就一目了然了,是FTPClien出现了问题,经过各方查找,由于设置了不合理的配置,会出现ftp假死的现象。下面给出以下解决办法

方法1(推荐).设置ftpClient为被动模式,并设置超时时间:


ftpClient.enterLocalPassiveMode(); // 使用被动模式
ftpClient.setConnectTimeout() 用于设置终端 SocketFTP 服务器建立连接这个过程的超时时间。
ftpClient.setDefaultTimeout() 用于设置终端的传输控制命令的 SocketSoTimeout,即针对传输控制命令的 Socket 的输入流做读取操作时每次陷入阻塞的超时时间。
ftpClient.setSoTimeout() 作用跟上个方法一样,区别仅在于该方法设置的超时会覆盖掉上个方法设置的值。
ftpClient.setDataTimeout() 用于设置终端的传输数据的 SocketSotimeout,即针对传输文件数据的 Socket 的输入流做读取操作时每次陷入阻塞的超时时间。
ftpClient.setControlKeepAliveTimeout() 用于设置当处于传输数据过程中,按指定的时间阈值定期让传输控制命令的 Socket 发送一个无操作命令 NOOP 给服务器,让它 keep alive。
ftpClient.setControlKeepAliveReplyTimeout():只有调用上个方法后,该方法才能生效,用于设置在传输数据这个过程中,暂时替换掉传输控制命令的 SocketSoTimeout,传输过程结束恢复这个 Socket 原本的 SoTimeout

方法2.或者自定义程序超时机制。实现方式有很多,比如时间轮算法、手动计算时长。下面给出使用Future的超时机制的参考代码。

try {
    Future < String > future = exec.submit(call);
    result = future.get(1000 * 3, TimeUnit.MILLISECONDS); //任务处理超时时间设为 3 秒
} catch(TimeoutException ex) {
    System.out.println("调用接口,处理超时......");
    ex.printStackTrace();
} catch(Exception e) {
    System.out.println("调用接口,处理失败......");
    e.printStackTrace();
}
如果你不想使用线程池,也可以采用传统的多线程方式来实现FTP客户端的大文件上传和下载功能。下面是一个简单的框架构思: 1. **主函数**: 开始时,创建两个单独的线程分别处理上传和下载任务。 ```cpp void uploadTask(const std::string& filePath); void downloadTask(const std::string& remotePath, const std::string& localPath); int main() { std::thread uploadThread(uploadTask, "file_to_upload"); std::thread downloadThread(downloadTask, "remote_file", "local_download_path"); // 等待两个线程结束 uploadThread.join(); downloadThread.join(); return 0; } ``` 2. **上传和下载函数**: 这些函数需要包含FTP连接的管理以及文件读写部分。 ```cpp void uploadTask(const std::string& filePath) { FtpConnection ftp; ftp.connect("ftp_server", "username", "password"); // 连接到FTP服务器 try { ftp.upload(filePath); // 执行上传操作 } catch (const FtpException& e) { handleException(e); } ftp.disconnect(); // 断开连接后关闭资源 } void downloadTask(const std::string& remotePath, const std::string& localPath) { FtpConnection ftp; ftp.connect("ftp_server", "username", "password"); try { ftp.download(remotePath, localPath); // 执行下载操作 } catch (const FtpException& e) { handleException(e); } ftp.disconnect(); } ``` 3. **异常处理**: 定义一个`handleException`函数,处理可能出现的FTP错误或者其他异常。 4. **文件I/O**: 利用C++标准库提供的`std::ifstream`和`std::ofstream`进行文件读取和写入,或者考虑第三方库如libcurl等来进行更复杂的数据传输。 5. **进度指示**: 可以通过定时检查任务状态或者直接询问FTP服务器获取上传/下载进度,然后更新UI展示。 6. **终止控制**: 提供一种方式让用户能够中断正在进行的任务,比如通过信号量或者在主函数中添加条件变量来协调停止信号。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值