在后台线程中终止长时间运行的任务

时间:2019-10-10 09:44:42

标签: 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 = 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 
                     }
                 }
             }
         }
     }
}

我在这样的普通线程中运行此方法:

new Thread(new Runnable() {
    @Override
    public void run() {
        writeCompressedData();
    }
});

或在后台工作线程中运行

TaskExecutor.queueRunnable(new Runnable() {
    @Override
    public void run() {
        writeCompressedData();
    }
});

问题是:此方法有时会出错,并在收到无效输入时导致无限循环。在这种情况下,即使设备屏幕关闭,它也将永久运行并损坏CPU ,这会提高设备的温度(如果使用工作线程,它还会阻塞等待队列中的其他任务)。

我认为我需要设置超时以终止长时间运行的任务。在普通Java线程中实现此目标的最佳方法是什么? RxJava支持吗?


我知道我需要修复的是“错误的”方法,而不仅仅是终止它。但是对于大型应用程序而言,很难控制其他开发人员的代码,而我首先需要避免影响用户。

4 个答案:

答案 0 :(得分:2)

您需要某种形式的协作取消,例如在一个或多个嵌套循环中检查Thread.currentThread().isInterrupted()

for (/* ... */) {
    if (Thread.currentThread().isInterrupted()) return;

    for (/* ... */) {

        if (Thread.currentThread().isInterrupted()) return;

        for (/* ... */) {
            // the tightest loop
        }             
    }
}

然后,当您运行该方法时,保持Thread / Future并调用interrupt / cancel(true)

backgroundTask = new Thread(() -> method());
backgroundTask.start();
// ...
backgroundTask.interrupt();

backgroundFuture = executorService.submit(() -> method());
// ...
backgroundFuture.cancel(true);

在RxJava中,它看起来像这样:

backgroundDisposable = Completable.fromAction(() -> method())
.subscribeOn(Schedulers.io()) // dedicated thread recommended
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> { /* done */ }, e -> { /* error */ });

// ...
backgroundDisposable.dispose();

答案 1 :(得分:1)

您可以将Java import jenkins.model.* RunList[] myBuilds = Jenkins.instance.getAllItems() .findAll{ it instanceof Job && it.getName() == {your job name} } .collect { it.getBuilds().byTimeStamp({your start date}, {your end date} } 与超时一起使用,而ExecutorService可以解决此问题。参见此Text editor to open big files

答案 2 :(得分:0)

更好的方法是在不同的进程中运行此类代码。即使进程崩溃,主进程也不会受到影响。

答案 3 :(得分:0)

我的方法是使用 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");
                    }
                });
    }

有关“超时”运算符的更多信息,请参见this