java - 可以暂停/恢复并执行用户的可运行操作的通用线程
问题描述
目的:为了创建一个独立于调用它的父类的通用线程类, 可以由调用它的父类启动/停止/暂停/恢复并执行用户定义的任务(通过可运行)
我的研究: SO_1 SO_2 SO_3 SO_4 SO_5 SomeBlog SomeBlog2 OracleBlog
问题:据我了解:
启动后台线程:将执行实现接口 的类
threadObj.start()
的函数语句。run()
Runnable
停止后台线程:
threadObj.interrupt()
将停止线程执行暂停线程:
threadObj.wait()
将暂停线程,尽管它需要额外的synchronised lock
机制- Resuming a thread :
threadObj.notifyAll()
将释放恢复对象,处理后synchronised lock mechanism
因此,基于此,我编写了一个通用 Thread 类,它应该通过 ui 按钮运行用户的一组任务和播放/暂停/恢复/停止,但它不起作用:
通用线程.java
public class PausibleThread extends Thread {
public static final String TAG ="PausibleThread>>";
@Nullable
PausibleRunnable runnable ;
public PausibleThread(@Nullable Runnable target) {
super(target);
PausibleRunnable r = new PausibleRunnable(target);
runnable=r;
}
@Override
public synchronized void start() { super.start(); }
public synchronized void stopThread(){ this.interrupt(); }
public synchronized void pauseThread(){ runnable.pause(); }
public synchronized void resumeThread(){ runnable.resume(); }
PausibleRunnable.java:
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class PausibleRunnable implements Runnable {
private Object lockerObject;
private boolean isPaused;
private boolean isFinished;
public static final String TAG="PausibleRunnable";
@Nullable
Runnable usrAction = null;
public PausibleRunnable(@NonNull Runnable usrAction) {
lockerObject = new Object();
isPaused = false;isFinished = false;
this.usrAction = usrAction;
}
public void run() {
while (!isFinished) {
if(isPaused) {
runPauseLoop();
}
else {
runUserAction();
isFinished=true;
}
}
}
private void runPauseLoop() {
synchronized (lockerObject) {
while (isPaused) {
try { lockerObject.wait(); }
catch (InterruptedException e) { e.printStackTrace(); }
}
}
}
private void runUserAction() {
if(usrAction !=null){ usrAction.run(); }
else { Log.e(TAG, "run: userAction is NULL" ); }
}
public void pause() {
synchronized (lockerObject) { isPaused = true; }
}
public void resume() {
synchronized (lockerObject) {
isPaused = false;
lockerObject.notifyAll();
}
}
}
Ui 创建一个 Pausible Thread 并实现它的各种功能:
//full class implementation at : https://paste.ubuntu.com/p/cTpW5Wt3Fy/
int totalRunTime = 20 * 5;
Pausible thread bgThread;
private void initThread() {
Runnable r = () -> {
try {
while (totalRunTime > 0) {
Thread.sleep(500);
totalRunTime--;
updateUi();
}
}
catch (Exception e) { e.printStackTrace(); }
};
bgThread = new PausibleThread(r);
}
private void updateUi() {
String data = "TotalRunTime=" + totalRunTime;
runOnUiThread(() -> tvTerminal.setText(data));
}
@Override
public void onClick(View v) {
if (bgThread == null) {
makeShortToast("Can't perform action, bg thread is null");
return;
}
if (v.getId() == fabPause.getId()) {bgThread.pauseThread(); }
else if (v.getId() == fabResume.getId()) { bgThread.resumeThread(); }
else if (v.getId() == fabStop.getId()) { bgThread.stopThread(); }
else if (v.getId() == fabStart.getId()) { bgThread.start(); }
}
但这不起作用。为什么?我在这里进行了疯狂的猜测,但我认为 runnable 只是运行用户的操作来运行一个大循环,而不是反复检查播放/暂停。那我该怎么办?
用户界面示例图片:https ://i.imgur.com/kmj3Bwt.png
解决方案
你问:“但这不起作用。为什么?”
我回答:你的解决方案不起作用,因为你总是在循环里面运行runUserAction
。你永远不会跳出那个循环来检查你是否被暂停。
恐怕你必须改造你的解决方案以在更短的循环中运行 usrAction,否则你将失去状态(假设你从外部中断该循环),这将导致未定义的行为,或者你只会打破当它结束时,或者你会在你不想暂停的状态下暂停你的循环[例如,在进行网络调用时——恢复后你会得到一个 SocketTimeoutException]。
我建议您使用前一种方法,因为它更优雅。
编辑:
另一种可能的解决方案:usrAction 中的每次迭代都检查PausableThread 的状态,即查看它是否暂停、停止或其他。
尝试这个:
PausableRunnable.java
public synchronized boolean canContinue() throws Exception {
synchronized (lockerObject) {
if (isPaused) {
lockerObject.wait();
}
if (isFinished) {
return false;
}
return true;
}
}
PausableThread.java
public boolean canContinue() throws Exception {
return runnable.canContinue();
}
和 Application.java
private void initThread() {
Runnable r = () -> {
try {
while (totalRunTime > 0) {
if (bgThread.canContinue()) { // <--- !!!!!!
Thread.sleep(200);
totalRunTime--;
updateUi();
}
}
}
catch (Exception e) { e.printStackTrace(); }
};
bgThread = new PausibleThread(r);
}
这样,您可以运行您的应用程序 Runnable,并且在可运行对象可以承受的时间仍然遵守 PausableThread 的状态。即在交易或其他不应中断的计算之前/之后。
编辑2:
随意在暂停或恢复等方法上丢失“同步”修饰符,因为您已经在其中的同步块中进行操作。
推荐阅读
- angular - 将较旧的 Angular 版本迁移到较新的 Angular 版本
- python - 无法重塑数组
- python - 我们如何使用 python 连接器连接到雪花
- tensorflow - Bazel 使用 tensorflow(或仅使用 tbb)作为外部依赖项具有“Make”Variables not defined 错误
- python - 用于动态变量的列表 - 与第一个和最后一个字符串一起传递的额外字符
- javascript - 节点中的空数组
- python - keras 根据列添加起始权重
- codeigniter - Codeigniter:index.php?按下后退按钮时删除
- csv - Java CSV:读取/写入具有多个标题行的 CSV
- uibutton - XCode 12 - iOS 14 - UIButton IBAction 不工作