Java 泛型代码 - 控制线程操作






3.76/5 (5投票s)
使用线程的一种更简单的方法。
引言
有时可能需要使用线程。最明显的一个场景是当你需要同时进行两个进程时。例如,在网页浏览器中加载网页。其中一个耗时的过程是实际加载 HTML、解析它,然后加载图像和网页所需的任何其他资源。然后,还有一个更新浏览器 GUI 的过程,例如显示进度指示器,并在网页加载时渲染网页内容。当耗时过程完成后,浏览器必须完成整个页面的渲染并激活任何交互元素,从而将控制权交还给用户。
ThreadAction
ThreadAction
类正是为了解决这个问题而设计的。通过扩展 ThreadAction
类,你必须重写三个方法,这些方法对应于场景的三个部分
- 需要完成的耗时过程。
- 一个简短的可重复过程,通常用于向用户更新第一个过程的进度。
- 一个在第一个过程完成后激活的过程,从而完成整个周期。
Java 代码
public abstract class ThreadAction implements Runnable {
// The sleep time between cycles of whilePerformingAction() invocations..
private int actionProgressSleep;
// True when the ThreadAction has completely finished any required processes..
private boolean actionFinished;
// True while the performAction() method has not completed its run yet..
private boolean actionPerforming;
// The Thread invoking the performAction() method..
private Thread actionRunner;
// The Thread invoking the whilePerformingAction() method..
private Thread actionProgress;
protected ThreadAction() {
reset();
}
protected Thread getThread(String name) {
// Return a new Thread; this method can be overridden to return a Thread from
// a Thread-Pool if you're using one..
return new Thread(this, name);
}
public void reset() {
// Set all values to default..
actionProgressSleep = 300;
actionFinished = true;
actionPerforming = false;
actionRunner = null;
actionProgress = null;
}
public void setActionProgressSleep(int sleepTime) {
// Are we active?
if (!isActionPerforming()) {
// Reset everything..
reset();
// Save the new sleep interval..
actionProgressSleep = sleepTime;
}
}
public void run() {
// Are we on the ActionRunner Thread?
if (actionRunner == Thread.currentThread()) {
// Perform the action..
performAction();
// Signal the ThreadAction that the action is finished..
actionPerforming = false;
// Are we on the ActionProgressRunner Thread?
} else if (actionProgress == Thread.currentThread()) {
// While we're still busy performing the main action..
while (actionPerforming) {
// Invoke the whilePerformingAction() method..
whilePerformingAction();
try {
// Send the ActionProgressRunner Thread to sleep..
Thread.currentThread().sleep(actionProgressSleep);
} catch (Exception ex) {
}
}
// Invoke the whenActionFinished() method since we're done..
whenActionFinished();
// Forget the Thread instances and signal that we're completely done..
actionRunner = null;
actionProgress = null;
actionFinished = true;
// Notify ourselves that we've finished the action process..
synchronized (this) {
notifyAll();
}
}
}
public void activateAction(boolean waitForAction) {
// Are we in the middle of processing an action already?
if (!isActionPerforming()) {
// Obtain a Thread to run the progress-update-process in..
if (actionProgress == null) {
actionProgress = getThread("ActionProgressUpdateThread");
}
// Obtain a Thread to run the time-consuming-process in..
if (actionRunner == null) {
actionRunner = getThread("ActionRunnerThread");
}
// Mark the action flags..
actionFinished = false;
actionPerforming = true;
// Start the Threads..
actionProgress.start();
actionRunner.start();
// Were we asked to wait for the action to complete before returning?
if (waitForAction) {
waitForAction();
}
}
}
public void waitForAction() {
// Are we in the middle of processing an action already?
if (isActionPerforming()) {
synchronized (this) {
try {
// Wait here until the action process completes..
wait();
} catch (InterruptedException ex) {
}
}
}
}
public boolean isActionPerforming() {
// Return True is the action is still running..
return actionPerforming || (!actionFinished);
}
// Specifies a time-consuming process executing when ThreadAction activates..
public abstract void performAction();
// Specifies a process to invoke repeatedly while performAction() is running..
public abstract void whilePerformingAction();
// Specifies a process to run at the end of performAction()..
public abstract void whenActionFinished();
}
测试代码
我们可以将一个 main(..)
方法添加到 ThreadAction
类中,或者将其添加到另一个类中,以测试 ThreadAction
的实际工作方式
public static void main(String[] args) {
ThreadAction ta = new ThreadAction() {
public void performAction() {
long time = System.currentTimeMillis() + 600;
while (time > System.currentTimeMillis()) {
System.out.println("| X | | |");
try {
Thread.sleep(250);
} catch (InterruptedException ex) {
}
}
}
public void whilePerformingAction() {
System.out.println("| | X | |");
}
public void whenActionFinished() {
System.out.println("| | | X |");
}
};
ta.setActionProgressSleep(200);
System.out.println("+---------+----------+----------+");
System.out.println("| Working | Updating | Complete |");
System.out.println("+---------+----------+----------+");
ta.activateAction(true);
System.out.println("+---------+----------+----------+");
}
如你所见,main(..)
方法定义了一个继承 ThreadAction
的内部类,并重写了 abstract
方法,使用简单的实现来打印一个“X
”字符,对应于该方法应该执行的操作。
在我的机器上,输出如下
+---------+----------+----------+
| Working | Updating | Complete |
+---------+----------+----------+
| | X | |
| X | | |
| | X | |
| X | | |
| | X | |
| X | | |
| | X | |
| | | X |
+---------+----------+----------+
请注意,使用值 True
发送到 activateAction(..)
方法来激活 ThreadAction
。如果改为使用 False
调用 activateAction(..)
,则来自 main
线程的打印将发生在我们的 ThreadAction
启动之前。
如果你没有使用 True
指定在 activateAction(..)
中激活 ThreadAction
,并且想要等待 ThreadAction
完成其过程,则可以在 ThreadAction
完成之前随时使用 waitForAction()
方法。
我在我的应用程序中使用了这个类来处理许多场景,例如登录、从数据库中获取复杂数据,任何需要一个后台进程与一个耗时进程同时进行的情况。
另一个例子
以下代码演示了在登录过程中使用 ThreadAction
public class LoginAction extends ThreadAction {
public String userName;
public String passWord;
public String networkResource;
private boolean loginFailed;
private int errorCode;
public void performAction() {
// Perform the log-in code, access the network-resource with the User-Name
// and Password, set the loginFailed flag to True or False accordingly
// and the errorCode with the corresponding result from the network
// resource.
}
public void whilePerformingAction() {
// Display some sort of login-progress-dialog, rotating logo or whatever is
// graphic animation was designed.
}
public void whenActionFinished() {
// If the login process succeeded, progress with the Application allowing the
// User to interact with the network-resource, if however, login has failed
// prompt the User to re-enter the password/username if there was an error
// with either.
}
}
请注意,ThreadAction
的设计使其实例可以在应用程序的生命周期内重复使用,并且还可以使用线程池类来提供线程,而不是每次调用 activateAction(..)
方法时都重新创建它们。
希望这个对你有帮助,祝你编码愉快。