Java 在后台线程内终止长时间运行的任务
我有一个压缩图像的任务,它在图像中使用许多循环:Java 在后台线程内终止长时间运行的任务,java,android,multithreading,rx-java,rx-android,Java,Android,Multithreading,Rx Java,Rx Android,我有一个压缩图像的任务,它在图像中使用许多循环: private void writeCompressedData() { int i, j, r, c, a, b; loat[][] inputArray; for (r = 0; r < minBlockHeight; r++) { for (c = 0; c < minBlockWidth; c++) { xpos = c * 8; pos
private void writeCompressedData() {
int i, j, r, c, a, b;
loat[][] inputArray;
for (r = 0; r < minBlockHeight; r++) {
for (c = 0; c < minBlockWidth; c++) {
xpos = c * 8;
pos = r * 8;
for (comp = 0; comp < jpegObj.numberOfComponents; comp++) {
inputArray = (float[][]) jpegObj.components[comp];
for (i = 0; i < jpegObj.VsampFactor[comp]; i++) {
for (j = 0; j < jpegObj.HsampFactor[comp]; j++) {
xblockoffset = j * 8;
yblockoffset = i * 8;
for (a = 0; a < 8; a++) {
for (b = 0; b < 8; b++) {
// Process some data and put to inputArray
}
}
// Encode Huffman block
}
}
}
}
}
}
或者在后台工作线程中运行
TaskExecutor.queueRunnable(new Runnable() {
@Override
public void run() {
writeCompressedData();
}
});
问题是:当接收到无效输入时,此方法有时会出错并导致无限循环。在这种情况下,它将永远运行,即使当设备的屏幕关闭时,也会伤害CPU,这会增加设备的温度(如果我使用工作线程,它还会阻止等待队列中的其他任务)
我想我需要设置一个超时来终止长时间运行的任务。在普通Java线程中实现这一点的最佳方法是什么?RxJava支持它吗
我知道我需要修复的是“错误”的方法,而不仅仅是终止它。但是对于大型应用程序,很难控制其他开发人员的代码,我需要做的第一件事就是避免影响用户。您可以使用Java
ExecutorService
和Future
来解决此问题。看看这个。更好的方法是在不同的进程中运行这样的代码。即使进程崩溃,主进程也将不受影响 您需要某种形式的协同取消,比如在一个或多个嵌套循环中检查Thread.currentThread().isInterrupted()
for (/* ... */) {
if (Thread.currentThread().isInterrupted()) return;
for (/* ... */) {
if (Thread.currentThread().isInterrupted()) return;
for (/* ... */) {
// the tightest loop
}
}
}
然后在运行该方法时,保持线程
/未来
并调用中断
/取消(true)
:
在RxJava中,这看起来像这样:
new Thread(new Runnable() {
@Override
public void run() {
writeCompressedData();
}
});
backgroundDisposable = Completable.fromAction(() -> method())
.subscribeOn(Schedulers.io()) // dedicated thread recommended
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> { /* done */ }, e -> { /* error */ });
// ...
backgroundDisposable.dispose();
我的方法是使用RxJava,更具体地说是使用RxJava的
Timeout
操作符,这里是代码的要点,5秒钟后将调用onError,因为在前5秒钟内没有发射物品
private void timeOutObserver() {
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) {
emitter.onNext("A");
}
})
.timeout(5000, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d("-@-", "subscribed");
}
@Override
public void onNext(String s) {
Log.d("-@-", "on next " + s);
}
@Override
public void onError(Throwable e) {
Log.d("-@-", e.getLocalizedMessage());
}
@Override
public void onComplete() {
Log.d("-@-", "on complete");
}
});
}
private void timeOutObserver(){
创建(新的ObservableOnSubscribe(){
@凌驾
公共无效订阅(可观测发射器){
发射器.onNext(“A”);
}
})
.超时(5000,时间单位为毫秒)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.订阅(新观察员){
@凌驾
认购的公共无效(一次性d){
Log.d(“-@-”,“认购”);
}
@凌驾
public void onNext(字符串s){
Log.d(“-@-”,“下一个”+s);
}
@凌驾
公共无效申报人(可丢弃的e){
Log.d(“-@-”,e.getLocalizedMessage());
}
@凌驾
未完成的公共空间(){
Log.d(“-@-”,“完成时”);
}
});
}
有关超时运算符的更多操作,请参阅,,但这将导致上下文切换成本。如果可能,您可以使用前台服务。它们的设计目的是让用户意识到某些进程正在后台运行,并在不再需要它时选择停止它。仅仅使用某种超时对我来说似乎是一个巨大的妥协。因为这只是一个小/快速的任务(只有当错误变大时),所以启动新服务对我来说似乎太大了。@nhoxbypass请分享你最终是如何做到这一点的,同时尝试rx方法shared@nhoxbypass在你的例子中,为了让这个例子起作用,在压缩代码成功的情况下更换发射器,默认情况下,如果在规定的时间内没有发射,它将抛出错误并停止执行,同样重要的是根据平台微调超时,就像如果平台是android,超时将在ANR内抛出一样。
private void timeOutObserver() {
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) {
emitter.onNext("A");
}
})
.timeout(5000, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d("-@-", "subscribed");
}
@Override
public void onNext(String s) {
Log.d("-@-", "on next " + s);
}
@Override
public void onError(Throwable e) {
Log.d("-@-", e.getLocalizedMessage());
}
@Override
public void onComplete() {
Log.d("-@-", "on complete");
}
});
}