2

我的疑问是关于如何在另一个线程的服务中的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(); 
} 

在运行这段代码,我得到一个例外“线程已经开始”

我没有读过关于这个的SO,已经启动的线程不能再次重新启动。我需要再次创建一个新线程并启动它。但是我不想每次都创建一个新的线程对象,因为这会导致UI线程的性能问题。有没有其他办法可以处理。

我发现了一些其他的方式来达到这个在android,如Handler,HandlerThread,AsyncTask等,但我不能解决我的想法是最好在这里使用(我不想创建新的对象每次(thread/asynctask/handler/handlerthread),只需要创建线程对象一次,并重新使用它每次)。

如果有人曾经在此领域工作过,请帮忙!

+0

您最好使用异步任务或处理程序。从长远来看,你会遇到许多问题,这些构造已经被制定出来并且培养你自己的解决方案也是需要创造的更多工作。只有在你想学习的时候才去做线程。 – allprog

+0

@allprog你可以看看我自己的答案。任何评论,我可以避免每次创建新的可运行对象(我现在正在这样做,因为我需要每次将新的参数传递给subB()和subC()。我认为只创建一次可运行对象会创建一个问题。) – superuser

回答

2

在进一步研究线程部分时,我设法发现使用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的新对象。需要了解我如何避免这种情况。

+0

创建对象很便宜(大多数情况下)。对于Android来说,如果你开始将函数想象成可以像Javascript一样传递的对象,那么它会有很大的帮助。尽可能避免可变字段,尽可能使用final关键字。这些代码正是在这些情况下需要完成的工作。如果并发执行subX不是问题,则使用AsyncTask而不是处理程序。做得好! – allprog

+1

还有一些注意事项:1.处理程序确保顺序执行,Runnables逐个执行。 2.如果runnable没有可变状态并且它始终在相同的输入数据上运行,那么重用它可能是安全的。但是,只要它不会产生问题,我会保留原样。目前是最安全的解决方案。 – allprog

+0

“,如果runnable没有可变状态并且它始终在相同的输入数据上运行,那么重用它可能是安全的。” - 我做到了。现在我的代码运行良好,并且每次都不创建任何新对象。 yey !! – 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(); 
    } 
} 

这是假设你想苏巴在主线程中的每个呼叫和subB的和subC的在后台线程。

1

if(mThread == null)块内移动mThread.start();。随后调用该方法时无条件地启动相同的线程。

+0

如果我这样做,subB()和subC()将只在第一次调用func()时运行。但是我希望它们每次都调用func(),并且每次都有新的参数。 – superuser

+0

看起来你真的可以使用'AsyncTask',然后为每个调用创建一个执行它的新实例。 – laalto

+0

也许我可以做到这一点。但是我不想每次都创建任何东西的新对象,因为这会将负载放在我的UI线程上。创建新对象需要很长时间,我们应该在关键的UI操作(AFAIK)期间避免这种情况。我想找到某种方式,比如,也许我可以创建一个AsyncTask的实例,以便第一次调用func(),并在每次后续调用func()时重新使用该对象。但是afaik,这对于AsyncTasks来说是不可能的?不确定Handler/HandlerThread。 – superuser

相关问题