65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.76/5 (5投票s)

2004 年 6 月 28 日

CPOL

2分钟阅读

viewsIcon

27582

使用线程的一种更简单的方法。

引言

有时可能需要使用线程。最明显的一个场景是当你需要同时进行两个进程时。例如,在网页浏览器中加载网页。其中一个耗时的过程是实际加载 HTML、解析它,然后加载图像和网页所需的任何其他资源。然后,还有一个更新浏览器 GUI 的过程,例如显示进度指示器,并在网页加载时渲染网页内容。当耗时过程完成后,浏览器必须完成整个页面的渲染并激活任何交互元素,从而将控制权交还给用户。

ThreadAction

ThreadAction 类正是为了解决这个问题而设计的。通过扩展 ThreadAction 类,你必须重写三个方法,这些方法对应于场景的三个部分

  1. 需要完成的耗时过程。
  2. 一个简短的可重复过程,通常用于向用户更新第一个过程的进度。
  3. 一个在第一个过程完成后激活的过程,从而完成整个周期。

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(..) 方法时都重新创建它们。

希望这个对你有帮助,祝你编码愉快。

© . All rights reserved.