重用相同的线程

时间:2018-02-25 19:26:06

标签: android

我有一个onClick()方法,里面有Thread。简化的结构如下。

imageA = (ImageView) findViewById(R.id.imageA);
imageA.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {myThread.start();}
});

Thread myThread = new Thread() {
    @Override
    public void run() {
        // some stuff here
    }
};

再次单击,我收到以下错误:

Thread already started

我在一些论坛中读到,不止一次启动Thread不是一个好主意而且使用它是不够的:

if (!myThread.isAlive()){myThread.start();}

建议的选项是创建新的Thread。问题是重复使用相同的Thread对我来说更舒服。所以问题是:

  1. 我是否应该避免重复使用相同的Thread
  2. 如果是,重写该代码的最佳做法是什么?
  3. 由于

4 个答案:

答案 0 :(得分:2)

  1. 您无法启动线程两次。看看at documentation
  2.   

    不止一次启动线程永远不合法。特别是,一旦完成执行,线程可能无法重新启动。

    1. 如果要重用线程,则可以使用ThreadPoolExecutor。但这也取决于您的具体情况 - 您希望在点击处理程序中执行的操作。您也可以查看AsyncTasks和Loaders。

答案 1 :(得分:1)

线程实例不能使用两次。

如果您想将相同的Thread重用于一系列任务,则应在Looper中使用Thread

 class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }

另一种直接使用的替代方法是使用HandlerThread

class MyHandlerThread extends HandlerThread {

    Handler handler;

    public MyHandlerThread(String name) {
        super(name);
    }

    @Override
    protected void onLooperPrepared() {
        handler = new Handler(getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                // process incoming messages here
                // this will run in non-ui/background thread
            }
        };
    }
}

然后您可以通过传递消息来完成任务

    //Create and send a new  message to looper
    fun sendMessage(messageToSend: String?) {
        //Create and post a new message to handler
        if (messageToSend != null && handler != null) {
            val encodeMessage = encodeMessage(messageToSend)
            handler!!.sendMessage(encodeMessage)
        } else {
            Log.e(TAG, "Looper is not prepared or message is Null")
            sendResultToUI("Looper is not prepared or message is Null")
        }
    }

    private fun encodeMessage(messageToSend: String): Message {
        val message = Message()
        val bundle = Bundle()
        bundle.putString(BUNDLE_KEY, messageToSend)
        message.data = bundle
        return message
    }

答案 2 :(得分:0)

在Thread ore对象上调用start方法将导致异常。如果您需要重用该线程,那么一旦完成其操作,您需要让它等待锁定。当您需要重用它时,您需要通知它唤醒。这可以在一个对象的帮助下,让它调用它锁定,一旦完成任务,你需要在synchronized块内调用lock.wait()(在锁定时同步)。当你再次需要它时,你只需在synchronized块中调用lock.notify()agin(在锁定时同步)。

通过使用Java并发包提供的Threadpool,可以避免上述复杂性。 Threadpool是一个线程对象池。它处理将任务分配给free(或新的,根据chosed threadpool)线程的复杂性,并在执行分配的工作后将对象返回到自由线程对象池。当新任务到来时,pool会将任务分配给其中一个免费线程。

答案 3 :(得分:0)

如果要重用线程,请使用具有大小为1的线程池的ExecutorService,或者您希望拥有多少线程,执行程序将重用它们。

ExecutorService executor = Executors.newFixedThreadPool(1);
        executor.execute(() -> {

        });