[Java][Android][Process] 暴力的服务能够解决一切,暴力的方式运行命令行语句
不管是在Java或者Android中运行命令行语句殊途同归都是创建一个子进程运行调用可运行文件运行命令。类似于Windows中的CMD一样。
此时你有两种方式运行:ProcessBuilder与Runtime;两种创建方式各有千秋,至于差别详见:[Java][Android][Process] ProcessBuilder与Runtime差别
在Android中创建子进程运行命令的时候有着一定的限制:
1.JVM提供的内存有限。
2.底层缓冲区间大小有限。
3.在高并发情况下easy造成堵塞。
基于上几点在运行命令行时我们不得不慎重操作。不能随便创建。
在上一篇文章中我提到:[Java][Android][Process] Process 创建+控制+分析 经验浅谈 了一些我的管理方式已经对实现的分析;其归根结底为:创建一个子进程的时候同一时候创建一个线程用于读取输出的流信息。在返回后及时退出。图示:
通过以上的控制方式能有效的解决掉底层ProcessManager线程死掉情况(出现等待IO缓冲区情况),当此线程死掉后子进程也将进入等待且永不退出。通过这种情况能达到运行上万条命令不出现故障。可是经过我半个月的观察发现其并非最稳定的方式,当程序中还有非常多其它IO操作如(文件读写。网络请求等)出现的时候;我运行到接近2万条命令行后出现了相同的问题。
查询后得出。尽管我们启动了线程来读取多余的流数据。可是当线程非常多或者请求非常多的时候线程可能来不及马上启动,而此时IO却已经满了,那么将会进入IO临界区等待,也就是说线程事实上不是万能的。庆幸的是在Android中有这样一种机制:服务。
Android服务是什么?我不多说百度一下就知道!
如今来说说我的新思路:
首先咱们创建一个服务,并设置服务为独立进程:android:process=".command.CommandService"
然后把实现部分放在我们开启的服务中。使用一个类来控制服务启动以及调用服务做任务,其任务就是把上面的部分放在服务中控制实现,如图:
这样看来是不是没有差别?事实上不然,差别已经来了,第一因为是独立进程的服务。所以会有独立的JVM空间,同一时候该进程的IO与主线程IO不是同一个(逻辑上);所以假设在主进程中操作其它的流并不影响独立进程的流。
而且有一个特别重要的情况:当独立服务进程出现死掉(IO)等待情况,这时服务中的守护进程将会自己主动杀掉自己。然后等待又一次启动后继续运行任务。
实现代码:
public CommandServiceImpl() {
//线程初始化
thread = new Thread(CommandServiceImpl.class.getName()) {
@Override
public void run() {
while (thread == this && !this.isInterrupted()) {
if (commandExecutors != null && commandExecutors.size() > 0) {
lock.lock();
LogUtil.i(TAG, "Executors Size:" + commandExecutors.size());
for (CommandExecutor executor : commandExecutors) {
if (executor.isTimeOut())
try {
killSelf();
} catch (RemoteException e) {
e.printStackTrace();
}
if (thread != this && this.isInterrupted())
break;
}
lock.unlock();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread.setDaemon(true);
thread.start();
}
<span style="white-space:pre"> </span>/**
* 杀掉自己
*
* @throws RemoteException
*/
@Override
public void killSelf() throws RemoteException {
android.os.Process.killProcess(android.os.Process.myPid());
}
/**
* 运行命令
*
* @param params 命令
* @return 结果
* @throws RemoteException
*/
@Override
public String command(String params) throws RemoteException {
CommandExecutor executor = CommandExecutor.create(params);
lock.lock();
commandExecutors.add(executor);
lock.unlock();
String result = executor.getResult();
lock.lock();
commandExecutors.remove(executor);
lock.unlock();
return result;
}
此时因为服务杀掉自己没法在内存中保存当前队列任务,那任务是否就丢弃掉呢?这肯定是不同意的,我们没法在服务中控制可是能够在控制任务的:
代码例如以下:
package net.qiujuer.libraries.genius.command; import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder; import net.qiujuer.libraries.genius.journal.LogUtil;
import net.qiujuer.libraries.genius.utils.GlobalValue; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by Genius on 2014/8/13.
* 命令运行Model
*/
public class CommandModel {
private static final String TAG = CommandModel.class.getName();
//调用服务接口
private static ICommandInterface iService = null;
//服务链接类,用于实例化服务接口
private static ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iLock.lock();
iService = ICommandInterface.Stub.asInterface(service);
if (iService != null) {
try {
iCondition.signalAll();
} catch (Exception e) {
e.printStackTrace();
}
} else
bindService();
iLock.unlock();
LogUtil.i(TAG, "onServiceConnected");
} @Override
public void onServiceDisconnected(ComponentName name) {
iService = null;
LogUtil.i(TAG, "onServiceDisconnected");
}
};
//锁
private static Lock iLock = new ReentrantLock();
//等待与唤醒
private static Condition iCondition = iLock.newCondition(); //运行參数
private String parameter;
//是否取消測试
private boolean isCancel; /**
* 实例化
*
* @param params @param params 命令參数 eg: "/system/bin/ping", "-c", "4", "-s", "100","www.qiujuer.net"
*/
public CommandModel(String... params) {
//check params
if (params == null)
throw new NullPointerException();
//run
StringBuilder sb = new StringBuilder();
for (String str : params) {
sb.append(str);
sb.append(" ");
}
this.parameter = sb.toString();
} /**
* 运行測试
*
* @param model ProcessModel
* @return 结果
*/
public static String command(CommandModel model) {
//检測是否取消測试
if (model.isCancel)
return null;
//check Service
if (iService == null) {
iLock.lock();
try {
iCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
iLock.unlock();
} String result;
try {
result = iService.command(model.parameter);
} catch (Exception e) {
e.printStackTrace();
bindService();
result = command(model);
}
return result;
} /**
* 启动并绑定服务
*/
private static void bindService() {
Context context = GlobalValue.getContext();
Intent intent = new Intent(context, CommandService.class);
context.startService(intent);
context.bindService(intent, conn, Context.BIND_AUTO_CREATE);
} /**
* 取消測试
*/
public void cancel() {
isCancel = true;
} /**
* 静态初始化
*/
static {
bindService();
} }
当中:
public static String command(CommandModel model) {
//检測是否取消測试
if (model.isCancel)
return null;
//check Service
if (iService == null) {
iLock.lock();
try {
iCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
iLock.unlock();
} String result;
try {
result = iService.command(model.parameter);
} catch (Exception e) {
e.printStackTrace();
bindService();
result = command(model);
}
return result;
}
採用回调,就是为了完毕任务运行的方法!
独立进程服务接口:ICommandInterface.aidl
interface ICommandInterface {
void killSelf();
String command(String params);
}
命令运行者(服务中的实际功能实现):CommandExecutor.java
package net.qiujuer.libraries.genius.command; import net.qiujuer.libraries.genius.journal.LogUtil;
import net.qiujuer.libraries.genius.utils.ToolUtil; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by Genius on 2014/8/13.
* 命令行运行命令
*/
class CommandExecutor {
private static final String TAG = CommandExecutor.class.getName();
//换行符
private static final String BREAK_LINE;
//错误缓冲
private static final byte[] BUFFER;
//缓冲区大小
private static final int BUFFER_LENGTH;
//创建进程时须要相互排斥进行
private static final Lock LOCK = new ReentrantLock();
//不能超过1分钟
private static final long TIMEOUT = 60000;
//ProcessBuilder
private static ProcessBuilder PRC; final private Process process;
final private InputStream in;
final private InputStream err;
final private OutputStream out;
final private StringBuilder sbReader; private BufferedReader bInReader = null;
private InputStreamReader isInReader = null;
private boolean isDone;
private long startTime; /**
* 静态变量初始化
*/
static {
BREAK_LINE = "\n";
BUFFER_LENGTH = 128;
BUFFER = new byte[BUFFER_LENGTH]; LOCK.lock();
PRC = new ProcessBuilder();
LOCK.unlock();
} /**
* 实例化一个CommandExecutor
*
* @param process Process
*/
private CommandExecutor(Process process) {
//init
this.startTime = System.currentTimeMillis();
this.process = process;
//get
out = process.getOutputStream();
in = process.getInputStream();
err = process.getErrorStream(); //in
if (in != null) {
isInReader = new InputStreamReader(in);
bInReader = new BufferedReader(isInReader, BUFFER_LENGTH);
} sbReader = new StringBuilder(); //start read thread
Thread processThread = new Thread(TAG) {
@Override
public void run() {
startRead();
}
};
processThread.setDaemon(true);
processThread.start();
} /**
* 运行命令
*
* @param param 命令參数 eg: "/system/bin/ping -c 4 -s 100 www.qiujuer.net"
*/
protected static CommandExecutor create(String param) {
String[] params = param.split(" ");
CommandExecutor processModel = null;
try {
LOCK.lock();
Process process = PRC.command(params)
.redirectErrorStream(true)
.start();
processModel = new CommandExecutor(process);
} catch (IOException e) {
e.printStackTrace();
} finally {
//sleep 100
ToolUtil.sleepIgnoreInterrupt(100);
LOCK.unlock();
}
return processModel;
} /**
* 获取是否超时
*
* @return 是否超时
*/
protected boolean isTimeOut() {
return ((System.currentTimeMillis() - startTime) >= TIMEOUT);
} //读取结果
private void read() {
String str;
//read In
try {
while ((str = bInReader.readLine()) != null) {
sbReader.append(str);
sbReader.append(BREAK_LINE);
}
} catch (Exception e) {
String err = e.getMessage();
if (err != null && err.length() > 0) {
LogUtil.e(TAG, "Read Exception:" + err);
}
}
} /**
* 启动线程进行异步读取结果
*/
private void startRead() {
//while to end
while (true) {
try {
process.exitValue();
//read last
read();
break;
} catch (IllegalThreadStateException e) {
read();
}
ToolUtil.sleepIgnoreInterrupt(50);
} //read end
int len;
if (in != null) {
try {
while ((len = in.read(BUFFER)) > 0) {
LogUtil.d(TAG, "Read End:" + len);
}
} catch (IOException e) {
String err = e.getMessage();
if (err != null && err.length() > 0)
LogUtil.e(TAG, "Read Thread IOException:" + err);
}
} //close
close();
//destroy
destroy();
//done
isDone = true; } /**
* 获取运行结果
*
* @return 结果
*/
protected String getResult() {
//until startRead en
while (!isDone) {
ToolUtil.sleepIgnoreInterrupt(200);
} //return
if (sbReader.length() == 0)
return null;
else
return sbReader.toString();
} /**
* 关闭全部流
*/
private void close() {
//close out
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//err
if (err != null) {
try {
err.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//in
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (isInReader != null) {
try {
isInReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bInReader != null) {
try {
bInReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} /**
* 销毁
*/
private void destroy() {
String str = process.toString();
try {
int i = str.indexOf("=") + 1;
int j = str.indexOf("]");
str = str.substring(i, j);
int pid = Integer.parseInt(str);
try {
android.os.Process.killProcess(pid);
} catch (Exception e) {
try {
process.destroy();
} catch (Exception ex) {
ex.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
好了本次採用暴力方式快要结束了,对于运行命令參数能够说是比較完美的运行方式了,採用这种方式我运行Ping測试达到10万次,并发达到500个任务同一时候运行没有问题。測试的设备为:魅族M9.
本次的代码我已经打包到自己的类库中。并开源到GitHub。地址:Genius-Android
希望大家多多迁移我的项目。该类库中还带有一个自己开发的完整的日志系统,以后还会增加其它东西,比方图片处理相关(模糊等)
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWl1anVlcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
[Java][Android][Process] 暴力的服务能够解决一切,暴力的方式运行命令行语句的更多相关文章
- [Java][Android][Process] Process 创建+控制+分析 经验浅谈
不管是Android亦或者Java中或多或少须要调用底层的一些命令.运行一些參数: 此时我们须要用到Java的Process来创建一个子进程.之所以是子进程是由于此进程依赖于发起创建请求的进程,假设发 ...
- [Java][Android][Process] 分享 Process 运行命令行封装类型
我在以前的文章中提到,使用Java不会有一个问题,创建运行命令来创建太多进程后创建进程行语句. [Android] ProcessBuilder与Runtime.getRuntime().exec分别 ...
- 转-"进程android.process.acore已意外停止" 解决办法
运行手机虚拟机时,老是弹出这样的“android.process.acore“服务已意外停止,虽不影响正常使用,但终究影响心情.网上找的方案,按如下步骤操作,可以解决问题: 出现这个提示不用担心,并不 ...
- windows下运行命令行mysql,提示mysql不是内部命令,解决办法
1. 打开CMD命令行,连接本地mysql数据库:mysql -u root -p 提示‘mysql’不是本地命令,解决办法如下: 找到你安装的mysql的目录,打开当前目录下的bin文件夹,你可以看 ...
- 零基础学Java(9)在mac上运行命令行提示"找不到或无法加载主类"
天坑 遇到的问题:使用命令行执行命令:java EightSample,会报以下错误 错误: 找不到或无法加载主类 EightSample 运行环境 mac系统 IntelliJ IDEA编译器 Ja ...
- windows删除服务的命令行语句
想要删除windows xp里的一个服务,怎么办呢? 系统没有可视化的工具可以用,不过内置了一个cmd命令 sc.exe 具体操作方法是:开始--运行--cmd,进入cmd命令行. 然后输入: sc ...
- Notepad++-第一篇命令行语句执行之编译、运行Java
1.让Notepad++编译和运行Java,在电脑上要已经配置好了Java的开发环境 2.在Notepad++上面的选项栏中找到 Plugins--->Plugin Admin 3.在Avail ...
- [Java][Android][Process] ProcessBuilder与Runtime差别
在Android中想要进行Ping,在不Root机器的情况下似乎还仅仅能进行底层命调用才干实现. 由于在Java中要进行ICMP包发送须要Root权限. 于是仅仅能通过创建进程来攻克了.创建进程在Ja ...
- 解决matplotlib库在PyCharm和命令行都无法正常显示问题
我们在学习人工智能的时候,会经常用到matplotlib,在学习的时候有一些例子写了代码运行: import matplotlib.pyplot as plt import numpy as np x ...
随机推荐
- javascript 库
http://overapi.com/javascript/ 查javascript http://slimerjs.org/ 自动测试? http://www.cnblogs.com/lhb25/p ...
- ORACLE【0】:基本操作
最新工作中用到oracle越来越多,自己虽然也能写点SQL.存储过程.触发器什么的,但是对数据库管理还是陌生的很,现在就将自己最近所学的一步一步整理下来. 1.windows上如何启动oracle 安 ...
- bzoj1857
三分的入门题,如果从AB上一点走到D是一个单峰函数从AB开始向CD传送带走的那个点也是一个单峰函数显然三分套三分 const eps=1e-5; var ax,ay,bx,by,cx,cy,dx,dy ...
- (1)java虚拟机概念和结构图
java虚拟机解构图一 java虚拟机解构图二 java虚拟机结构图三 [1]类加载系统 --->负责从文件系统或网络中加载class信息,存放至方法区的内存空间[2]java堆 ...
- NET下RabbitMQ实践[示例篇]
在上一篇文章中,介绍了在window环境下安装erlang,rabbitmq-server,以免配置用户,权限,虚拟机等内容. 今天将会介绍如果使用rabbitmq进行简单的消息入队, ...
- CF GYM 100703F Game of words
题意:两个人玩n个游戏,给出每人玩每个游戏的时间,两个人需要在n个游戏中挑m个轮流玩,求最短时间. 解法:dp.(这场dp真多啊……话说也可以用最小费用最大流做……然而并不会XD)dp[i][j][k ...
- Java内存结构、类的初始化、及对象构造过程
概述 网上关于该题目的文章已经很多,我觉得把它们几个关联起来讲可能更好理解一下.与其它语言一样,它在执行我们写的程序前要先分配内存空间,以便于存放代码.数据:程序的执行过程其实依然是代码的执行及数据的 ...
- javascript设计模式8
桥接模式(将抽象与其实现隔离开来,以便二者独立变化) function sendInfo(element){ var id=element.id; ajax("GET"," ...
- Bzoj 4403: 序列统计 Lucas定理,组合数学,数论
4403: 序列统计 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 328 Solved: 162[Submit][Status][Discuss] ...
- leetcode@ [263/264] Ugly Numbers & Ugly Number II
https://leetcode.com/problems/ugly-number/ Write a program to check whether a given number is an ugl ...