在单独的线程上运行一段代码

4

我的问题是关于如何在我的服务的API中在另一个线程中运行一段代码。

我有一个API函数在我的服务中。只有这个API代码的一部分(2-3 LOC)是独立的,我想将它移动到单独的线程中,因为这些代码占用了很长时间,而且这些代码对UI线程目前没有影响。这是我所做的。

原始代码:

func(){
    subA();
    subB();
    subC();
}

修改后的代码:

Thread mThread = null;
func(){
    subA();
    if(mThread == null){
        mThread = new Thread(){
            public void run(){
                subB();
                subC();
            }
        } 
    }
    mThread.start();
}

运行此代码时,我会收到一个“线程已经启动”的异常。
我在Stack Overflow上读到过,已经启动的线程不能再次启动。我需要再次创建一个新的线程并启动它。但是,我不想每次都创建一个新的线程对象,因为这会导致UI线程性能问题。有没有其他方法可以处理这个问题?
我在Android中发现了另外几种方法,如Handler、HandlerThread、AsyncTask等。但我无法确定哪种方法最适合在这里使用(我不想每次都创建新的thread/asynctask/handler/handlerthread对象,只想创建一次线程对象并每次重用它)。
如果有人在这个领域工作过,请帮忙!

你最好使用异步任务或处理程序。从长远来看,你会遇到很多这些结构所设计的问题,而自己创造解决方案也需要更多的工作量。如果你想学习,请使用线程。 - allprog
@allprog 你能看一下我的答案吗?有什么评论,我如何避免每次创建新的可运行对象(我现在正在这样做,因为我需要每次传递新的参数给subB()和subC()。而且我认为只创建一个可运行对象会产生问题。) - superuser
3个回答

3

进一步研究线程部分后,我发现使用ThreadHandler比使用线程+循环器更简单(因为ThreadHandler默认附有循环器,并且能够良好管理)。因此,现在我正在寻找这段代码。

HandlerThread mThread = null; 
Handler mHandler = null; 
func(){ 
   subA(); 
    if(mThread == null){
        mThread = new HandlerThread("mThread"); 
        mThread.start();
        mHandler = new Handler(mThread.getLooper());
    } 
    mHandler.post(new Runnable(){
    public void run(){
        subB(); 
        subC();
    }});
}

但我发现这段代码存在一个问题,每次调用func()仍然需要创建一个新的runnable对象。需要找出如何避免此问题。


创建对象通常很便宜。在Android中,如果您开始将函数视为可以像Javascript一样传递的对象,则会有很大帮助。尽可能避免可变字段,尽可能使用final关键字。这段代码正是在这些情况下需要完成的工作。如果子X的并发执行不是问题,则请改用AsyncTask而不是处理程序。干得好! - allprog
1
一些额外的注意事项:1.处理程序确保顺序执行,Runnables一个接一个地执行。2.如果runnable没有可变状态,并且它始终在相同的输入数据上操作,则很可能可以安全地重用它。但是,只要不会出现问题,我会将代码保留原样。当前是最安全的解决方案。 - allprog
如果可运行对象没有可变状态,并且始终对相同的输入数据进行操作,则很可能可以安全地重用它。- 我做到了。现在我的代码运行良好,而且每次都不会创建任何新对象。耶!! - superuser

1
你只能启动一次线程,这就是为什么会出现错误的原因。
简单的解决方法是使用队列。让线程在一个无限循环中从队列中读取内容,让其他线程将需要执行的“工作”放入队列中。
以下是一个类似于你的示例的示例(更新为使用阻塞接口):
Thread mThread = null;
void func(String dataToWorkWith) {
    final BlockingQueue<String> q = new ArrayBlockingQueue<String>(1000);
    subA();
    q.add("some data if you need it");
    if(mThread == null) {
        mThread = new Thread() {
            public void run() {
                while(true) {
                    try {
                        final String dataToWorkWith = q.take();
                        subB(dataToWorkWith);
                        subC(dataToWorkWith);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        };
        mThread.start();
    }
}

假设您希望每次调用主线程中的subA,以及在后台线程中运行subB和subC。

1
mThread.start();移至if(mThread == null)块内。在对该方法进行后续调用时,无条件地启动相同的线程。

如果我这样做,subB()和subC()只会在第一次调用func()时运行。但是我希望它们在每次独立调用func()时都能运行,并且每次都有新的参数。 - superuser
看起来你真的需要一个 AsyncTask,为每个调用创建和执行一个新实例。 - laalto
也许我可以做到。但是我不想每次都创建一个新对象,因为那会给我的UI线程带来负荷。创建新对象需要大量时间,我们应该在关键的UI操作期间避免这样做(就我所知)。我想找到一些方法,比如,也许我可以为第一次对func()的调用创建AsyncTask实例,并重复使用该对象以进行每个后续对func()的调用。但是据我所知,这在AsyncTasks中不可能实现?不确定Handler / HandlerThread。 - superuser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接