网站首页 > java教程 正文
知乎编辑器效果有限,原文发布在语雀文档上,看上去效果更好~
Java—用ProcessBuilder执行Shell任务 · https://zhuanlan.zhihu.com/p/62766073
概述
在Java中执行Shell任务可以用两种方式:1.java.lang下的Runtime 2.java.lang下的ProcessBuilder
但是,通过源码可以发现,二者最终都是通过ProcessBuilder类来执行操作的。为了在Java中执行大数据中的shell任务,添加任务失败重试次数、成功/失败消费者,我们可以设计如下几个类:
- ShellMonitor
- ShellTask
- Task
- StreamGobbler
ShellMonitor
主要是ShellTask的监控和管理,定义了失败重试方法、任务失败/成功后的消费者、以及Task实体对象
ShellTask
执行任务的主体,继承了抽象类Task
Task
抽象类,定义了所有任务的公共属性:任务重试次数:retryNum、cmdTextConsumer(cmd输出消费者)、任务失败后的回调(消费者)failedCallback、任务成功后的回调(successCallback)
StreamGobbler
日志流接收类,用于处理ProcessBuilder执行时的输入/输出/错误流
ProcessBuilder
Java.lang包下的,用于在Java中执行shell的类,文章后有详细介绍。
任务执行示例
启动一个Shell任务很简单,就2句:
ShellTask shellTask = new ShellTask(confList.toArray(new String[confList.size()]));
new ShellMonitor<String>(shellTask, logger::info, null, null).run();
1.将List<String>类型的commands转化为String[],并new一个ShellTask任务
2.new一个ShellMonitor将该ShellTask放进去,配置任务成功/失败消费者为空,然后执行run()
相关类说明
1.ShellMonitor
主要属性
task
即任务执行的主体
failedTimes
属性记录了Task失败次数
failureConsumer successConsumer
则分别对应失败/成功后的消费者(消费者还是个Task任务)
主要方法
run()
主要的方法run(),调用task的run()
redo()
失败重试方法,在失败次数 < Task中定义的失败重试次数时,调用redo()方法
2.ShellTask
ShellTask即任务执行的主体类,继承了抽象类Task,并重新了run()和redo()方法
?
主要属性
commands
String[],装的是执行的参数集合
path
执行shell时需要用到的文件
构造函数
三种构造器:
无参、带String[]参数、带File和String[]构造器
主要方法
run()
run方法即执行的主方法,在其中调用runCommand()具体执行
redo()
失败重试方法,在其中调用runCommand()具体执行
runCommand()
执行的主方法,具体如下:
public void runCommand() {
try {
logger.info("start");
long start = System.nanoTime();
ProcessBuilder builder = new ProcessBuilder();
builder.command(commands);
builder.directory(path == null ? FileUtils.getUserDirectory() : path);
//启动工作线程
Process process = builder.start();
//启动日志流记录线程
StreamGobbler streamGobbler =
new StreamGobbler(process.getInputStream(), process.getErrorStream(), super.cmdTextConsumer);
new Thread(streamGobbler).start();
int exitCode = process.waitFor();
long end = System.nanoTime();
if (exitCode == 0) {
if (successCallback != null)
super.successCallback.accept(this);
} else {
if (failedCallback != null)
super.failedCallback.accept(this);
}
logger.info("ec=" + exitCode);
logger.info("end");
logger.info("duration:" + ((double) (end - start) / 10e8));
} catch (Exception e) {
e.printStackTrace();
}
}
程序逻辑很简单,启动ProcessBuilder工作线程、启动StreamGobbler记录线程。通过exitCode获取工作线程的执行状态码,0表示运行正常结束,如果正常结束则调用任务成功消费者、否则调用失败消费者(如果定义了消费者)
3.Task
Task是一个抽象类实现了Runnable接口,提供了所有任务的抽象方法和通用属性字段
?主要属性
retryNum
任务失败重试次数,默认为3次
failedCallback
任务失败时的消费者
successCallback
任务成功时的消费者
构造函数
三种构造器:
无参、带String[]参数、带File和String[]构造器
主要方法
run()
重新runnable接口中的run()
redo()
失败重试方法
4.StreamGobbler
实现了Runnable接口的一个线程类,用于任务执行过程中的输出流、错误流
?主要run方法如下:
public void run() {
Runnable inputRunnable = () -> new BufferedReader(new InputStreamReader(inputStream)).lines().forEach(consumer);
Runnable errorRunnable = () -> new BufferedReader(new InputStreamReader(errorStream)).lines().forEach(consumer);
new Thread(inputRunnable).start();
new Thread(errorRunnable).start();
}
此类分别启动两个线程,用于直接打印任务运行时的正常输出和错误输出
5.ProcessBuilder
ProcessBuilder类是Java1.5在java.lang中新添加的一个新类,此类用于创建操作系统进程,它提供一种启动和管理进程(也就是应用程序)的方法。在1.5之前,都是由Process类处理实现进程的控制管理。每个 ProcessBuilder 实例管理一个进程属性集。它的start() 方法利用这些属性创建一个新的 Process 实例。start() 方法可以从同一实例重复调用,以利用相同的或相关的属性创建新的子进程。
具体可以参考:https://blog.csdn.net/u013256816/article/details/54603910
主要属性
点进去ProcessBuilder的源码看看:
?
可见有五个属性,其中command是shell命令,directory是shell中会用到的文件,environment环境配置,还有个布尔值,是否重定向错误流,以及redirects[]重定向数组。一般情况下,只需要用到command。
构造函数
查看类的构造器,可以看到有两种:
?
这两个构造器中command字段,分别接受List<String>和String[]类型的参数,最终都会将command转化为List<String>类型
主要方法
略...
好久没写文章了,一是工作忙了,最主要是人变懒了,不过我又回来了,后面的文章还是会不断出来~重点是Java基本经典的书、读书笔记类型的,过一遍然后Java就暂时放一边(项目中比较常用的,经典的代码还是会记录下)。
后面就是AI深度学习、图像识别的东西~
- 上一篇: 面试官:请用Java实现一个HTTP请求
- 下一篇: Java中常用的API——阿里架构师的两万字总结
猜你喜欢
- 2024-12-10 《JAVA编程思想》5分钟速成:第18章(Java的IO系统)
- 2024-12-10 Hook技术简介
- 2024-12-10 Tomcat 配置详解和调优
- 2024-12-10 「故障演练」 Redis Cluster集群,当master宕机,主从切换
- 2024-12-10 一次完整的HTTP请求与响应涉及了哪些知识?
- 2024-12-10 一款超牛逼的 Linux 终端复用神器(附安装、使用教程)
- 2024-12-10 Java中常用的API——阿里架构师的两万字总结
- 2024-12-10 面试官:请用Java实现一个HTTP请求
- 2024-12-10 Nice,终于有人把SpringMVC讲明白了,太简单了...
- 2024-12-10 Java11新特性-效能翻倍的HttpClient
你 发表评论:
欢迎- 最近发表
-
- 多种负载均衡算法及其Java代码实现
- 输入www.baidu.com背后经历了啥?说清楚这个,已经超过90%的人了
- 优化MySQL:为什么你应该用 UNSIGNED INT 存储IP地址
- 实模式下CPU如何获取数据及指令(实模式寻址方式)
- java基础都在这了,小主们拿去吧(java基础是指什么)
- 盘点爬虫语言为何选择Python而不是Java
- 搭载Dubbo+Zookeeper踩了这么多坑,我终于决定写下这篇
- 网络协议之TCP/IP协议(面试必考内容) - javaEE初阶 - 细节狂魔
- 深夜报警!10亿次请求暴击,如何用Redis找出最热IP?
- VPN技术(IPsec/L2TP/SSLVPN/PPTP)学习笔记
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)