Android Thread线程

ゝ一世哀愁。 2022-08-01 15:35 249阅读 0赞
  1. 相信大家对线程肯定不陌生,我们在编程的过程中经常要用到线程,Android提供了多线程支持,在Android程序中,VM采用抢占式调度模式对线程进行调度(基于线程优先级来决定CPU的使用权),android一个重要的机制就是线程+消息。

一,线程进程

  1. 既然说到线程,得先说说进程。一般来说一个android程序对于一个进程(组件元素activityservicereceiverprovider。都有一个process属性可以指定组件运行在哪个进程中,你可以在清单文件中manifest设置组件的进程)所有的组件都在特定进程的主线程中实例化。
  2. 线程:线程是属于进程的。同一个进程下的可以有多个线程。这些线程是共同享该进程占有的资源和地址空间的。线程是进程的一部分,一个没有线程的进程可以看做是单线程的。对于android应用来说,当一个应用启动的时候,系统会默认为它创建一个线程,称为“主线程”(UI线程)。这个线程很重要因为它负责处理调度事件到相关的 user interface widgets,包括绘制事件。你的应用也是在这个线程里面与来自Android UI toolkit (包括来自 android.widget android.view 包的组件)的组件进行交互。因此,这个主线程有时候也被称为 UI 线程。

进程线程总结:

  1. 进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能。
  2. 进程是操作系统进行资源分配的基本单位。
  3. 线程是操作系统进行调度的基本单。
  4. 线程的划分尺度小于进程,线程隶属于某个进程。
  5. 进程是程序的一种动态形式,是CPU、内存等资源占用的基本单位,而线程是不能独立的占有这些资源的。
  6. 进程之间相互独立,通信比较困难,而线程之间共享一块内存区域,通信比较方便。
  7. 进程在执行过程中,包含比较固定的入口、执行顺序和出口,而线程的这些过程会被应用程序所控制。

二,线程的实现(两种方式)

  1. 两种方法,继承Thread类和实现Runnable接口
  • 继承Thread类

    1. extends Thread 重写run方法做我们想做的事情,start启动线程。 简单代码如下:

    @Override

    1. protected void onCreate(Bundle savedInstanceState) {
    2. super.onCreate(savedInstanceState);
    3. setContentView(R.layout.activity_main);
    4. new CustomerThread("CustomerThread").start();
    5. }
    6. public class CustomerThread extends Thread {
    7. public CustomerThread(String threadName) {
    8. super(threadName);
    9. }
    10. @Override
    11. public void run() {
    12. /** do our things */
    13. }
    14. }
  • 实现Runnable接口:run方法里面做我们要做的事情。简单代码如下

    @Override

    1. protected void onCreate(Bundle savedInstanceState) {
    2. super.onCreate(savedInstanceState);
    3. setContentView(R.layout.activity_main);
    4. SyncRunnable syncRunnable = new SyncRunnable();
    5. Thread thread = new Thread(syncRunnable, "syncRunnable");
    6. thread.start();
    7. }
    8. public class SyncRunnable implements Runnable {
    9. @Override
    10. public void run() {
    11. synchronized (this) {
    12. for (int i = 0; i < 5; i++) {
    13. System.out.println(Thread.currentThread().getName() + " synchronizedloop " + i);
    14. }
    15. }
    16. }
    17. }

注:这两种方法的实现中我都有带上线程的名字。顺便说一点,我们用线程的时候最好给线程加上一个名字,这样我们在看log信息的时候能方便的知道是哪个线程打(默认会thread-0, thread-1什么的)。

三,线程退出

  1. 我们在使用线程的时候经常会碰到这种情况,我们的线程是要一直while执行的(如果不是要一直while执行的thread执行完了就会自动销毁)。这个时候当程序退出的时候我们想要这个while线程也去释放资源。主要有三种方式。
  • 使用退出标志,使线程正常退出
    这个最简单了设置标志位。简单代码如下:

    private boolean exit = false;

    1. @Override
    2. protected void onCreate(Bundle savedInstanceState) {
    3. super.onCreate(savedInstanceState);
    4. setContentView(R.layout.activity_main);
    5. SyncThread syncRunnable = new SyncThread("syncThread");
    6. syncRunnable.start();
    7. }
    8. @Override
    9. protected void onDestroy() {
    10. exit = true;
    11. super.onDestroy();
    12. }
    13. public class SyncThread extends Thread {
    14. public SyncThread(String threadName) {
    15. super(threadName);
    16. }
    17. @Override
    18. public void run() {
    19. while(!exit) {
    20. /** do our things */
    21. }
    22. }
    23. }

在onDestroy方法里面退出。exit = true;

  • 使用interrupt()方法中断线程 (当调用线程的interrupt()方法时,系统会抛出一个InterruptedException异常)
    1)先捕获InterruptedException异常之后通过break来跳出循环,简单代码如下。

    SyncThread syncRunnable = null;

    1. @Override
    2. protected void onCreate(Bundle savedInstanceState) {
    3. super.onCreate(savedInstanceState);
    4. setContentView(R.layout.activity_main);
    5. syncRunnable = new SyncThread("syncThread");
    6. syncRunnable.start();
    7. }
    8. @Override
    9. protected void onDestroy() {
    10. if (null != syncRunnable) {
    11. syncRunnable.interrupt();
    12. }
    13. super.onDestroy();
    14. }
    15. public class SyncThread extends Thread {
    16. public SyncThread(String threadName) {
    17. super(threadName);
    18. }
    19. @Override
    20. public void run() {
    21. while(true) {
    22. /** do our things */
    23. try {
    24. Thread.sleep(5*1000);
    25. } catch (InterruptedException e) {
    26. e.printStackTrace();
    27. /** exit the while */
    28. break;
    29. }
    30. }
    31. }
    32. }

    2)使用isInterrupted()判断线程的中断标志来退出循环。简单代码如下

    SyncThread syncRunnable = null;

    1. @Override
    2. protected void onCreate(Bundle savedInstanceState) {
    3. super.onCreate(savedInstanceState);
    4. setContentView(R.layout.activity_main);
    5. syncRunnable = new SyncThread("syncThread");
    6. syncRunnable.start();
    7. }
    8. @Override
    9. protected void onDestroy() {
    10. if (null != syncRunnable) {
    11. syncRunnable.interrupt();
    12. }
    13. super.onDestroy();
    14. }
    15. public class SyncThread extends Thread {
    16. public SyncThread(String threadName) {
    17. super(threadName);
    18. }
    19. @Override
    20. public void run() {
    21. while(!isInterrupted()) {
    22. /** do our things */
    23. }
    24. }
    25. }

    3)两者结合使用(推荐) 在线程未进入阻塞的代码段时通过isInterrupted()判断中断来退出循环,在进入阻塞状态后通过通过捕获中断异常来退出循环,简单代码如下

    SyncThread syncRunnable = null;

    1. @Override
    2. protected void onCreate(Bundle savedInstanceState) {
    3. super.onCreate(savedInstanceState);
    4. setContentView(R.layout.activity_main);
    5. syncRunnable = new SyncThread("syncThread");
    6. syncRunnable.start();
    7. }
    8. @Override
    9. protected void onDestroy() {
    10. if (null != syncRunnable) {
    11. syncRunnable.interrupt();
    12. }
    13. super.onDestroy();
    14. }
    15. public class SyncThread extends Thread {
    16. public SyncThread(String threadName) {
    17. super(threadName);
    18. }
    19. @Override
    20. public void run() {
    21. while(!isInterrupted()) {
    22. /** do our things */
    23. try{
    24. Thread.sleep(5*1000);
    25. }catch(InterruptedException e){
    26. e.printStackTrace();
    27. break;
    28. }
    29. }
    30. }
    31. }
  • 使用stop方法强行终止线程(不推荐使用,可能发生不可预料的结果)
    thread.stop() 不安全主要是:thread.stop()调用之后,创建子线程的线程就会抛出ThreadDeatherror的错误,并且会释放子线程所持有的所有锁。一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用thread.stop()后导致了该线程所持有的所有锁的突然释放(不可控制),那么被保护数据就有可能呈现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。

四,多线程通信

  • 管道(pipe)属于linux范畴:一条“管道”为两个线程建立一个单向的通道。生产者负责写数据,消费者负责读取数据。简单代码如下

    private PipedReader mRead;

    1. private PipedWriter mWrite;
    2. private Thread mThread;
    3. @Override
    4. protected void onCreate(Bundle savedInstanceState) {
    5. super.onCreate(savedInstanceState);
    6. setContentView(R.layout.activity_main);
    7. initData();
    8. try {
    9. mWrite.write("pipe");
    10. } catch (IOException e) {
    11. e.printStackTrace();
    12. }
    13. }
    14. @Override
    15. protected void onDestroy() {
    16. super.onDestroy();
    17. mThread.interrupt();
    18. try {
    19. mRead.close();
    20. mWrite.close();
    21. } catch (IOException e) {
    22. }
    23. }
    24. private void initData() {
    25. mRead = new PipedReader();
    26. mWrite = new PipedWriter();
    27. try {
    28. mWrite.connect(mRead);
    29. } catch (IOException e) {
    30. e.printStackTrace();
    31. }
    32. mThread = new Thread(new ThreadPipe(mRead), "ThreadPipe");
    33. mThread.start();
    34. }
    35. private static class ThreadPipe implements Runnable {
    36. private final PipedReader reader;
    37. public ThreadPipe(PipedReader reader){
    38. this.reader = reader;
    39. }
    40. @Override
    41. public void run() {
    42. while(!Thread.currentThread().isInterrupted()){
    43. try {
    44. int i;
    45. while((i = reader.read()) != -1){
    46. char c = (char) i;
    47. Log.d("vae_tag", "char = " + c);
    48. }
    49. } catch (IOException e) {
    50. e.printStackTrace();
    51. }
    52. }
    53. }
    54. }

先把PipedReader,PipedWriter关联起来。如mWrite.connect(mRead);然后这里是在UI线程里面写,ThreadPipe 线程里面读log出来。

  • 共享内存:一个变量可以同时被多个线程所访问。这里要特别注意同步和原子操作的问题,这也共享内存容易出错的原因所在,容易出现死锁等。
  • socket:这个应该简单。
  • 消息队列(Hander和Message):这个也是android常用的线程间通信方式,网上也有好多关于这个的博文。主要要理清Thread, Handler,Message,Looper,MessageQueue 之间的关系。
  1. * Looper:(相当于隧道) 一个线程可以产生一个Looper 对象,Looper负责的就是创建管理一个MessageQueue
  2. * MessageQueue(消息队列):里面放的就是Message对象,每一个线程最多只可以拥有一个MessageQueue,通常使用一个Looper对象对该线程的MessageQueue进行管理,每一个MessageQueue都不能脱离Looper而存在。主线程创建时会默认创建MessageQueue,其他的线程不会默认创建。
  3. * Message(消息):被放入在MessageQueue中。
  4. * Handler(消息的处理者):Handler负责将需要传递的信息封装成Message,通过调用Handler对象的obtainMessage()来实现,将消息传递给Looper,这是通过Handler对象的sendMessage()来实现的。继而由LooperMessage放入MessageQueue中。当Looper对象看到MessageQueue中含有Message,就将其广播出去。该Handler对象收到该消息后,调用相应的Handler对象的handleMessage()方法对其进行处理。简单来说就是当要发送Message消息的时候Handler告诉对应ThreadLooper有消息到来,LooperMessage放入到MessageQueue当中去。当MessageQueue中有Message的时候该ThreadLooper告诉对应的ThreadHandler来处理消息。
  5. 几个简单例子代码。
  6. 1UI线程给自己发送消息。
  7. private Handler handler;
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_main);
  12. handler = new HandlerTest(getMainLooper());
  13. Message msg = handler.obtainMessage(1, 1, 1, "UI thread send message");
  14. handler.sendMessage(msg);
  15. }
  16. class HandlerTest extends Handler {
  17. public HandlerTest(Looper looper) {
  18. super(looper);
  19. }
  20. public void handleMessage(Message msg) {
  21. super.handleMessage(msg);
  22. Log.d("vae_tag", (String)msg.obj);
  23. }
  24. }
  25. 2UI线程给其他线程发送消息。
  26. private Button mButton;
  27. private Handler handler;
  28. @Override
  29. protected void onCreate(Bundle savedInstanceState) {
  30. super.onCreate(savedInstanceState);
  31. setContentView(R.layout.activity_main);
  32. mButton = (Button) findViewById(R.id.send_message_id);
  33. new ChildThread("ChildThread").start();
  34. mButton.setOnClickListener(new View.OnClickListener() {
  35. @Override
  36. public void onClick(View v) {
  37. handler.obtainMessage(1, "UI thread send to child thread").sendToTarget();
  38. }
  39. });
  40. }
  41. class ChildThread extends Thread {
  42. public ChildThread(String threadName) {
  43. super(threadName);
  44. }
  45. public void run() {
  46. Looper.prepare();/** init Looper */
  47. handler = new ThreadHandler(Looper.myLooper());
  48. Looper.loop(); /** start Looper */
  49. }
  50. class ThreadHandler extends Handler {
  51. public ThreadHandler(Looper looper) {
  52. super(looper);
  53. }
  54. public void handleMessage(Message msg) {
  55. Log.d("vae_tag", "child thread receive the message :" + msg.obj);
  56. }
  57. }
  58. }
  59. 3)其他线程给UI线程发送消息。
  60. private Handler handler;
  61. @Override
  62. protected void onCreate(Bundle savedInstanceState) {
  63. super.onCreate(savedInstanceState);
  64. setContentView(R.layout.activity_main);
  65. new ChildThread("ChildThread").start();
  66. }
  67. class HandlerTest extends Handler {
  68. public HandlerTest(Looper looper) {
  69. super(looper);
  70. }
  71. public void handleMessage(Message msg) {
  72. super.handleMessage(msg);
  73. Log.d("vae_tag", (String) msg.obj);
  74. }
  75. }
  76. class ChildThread extends Thread {
  77. public ChildThread(String threadName) {
  78. super(threadName);
  79. }
  80. public void run() {
  81. handler = new HandlerTest(Looper.getMainLooper());
  82. Message msg = handler.obtainMessage(1, 1, 1, "child thread send the message");
  83. handler.sendMessage(msg);
  84. }
  85. }
  86. 4)其他线程给其他线程发
  87. private Handler handler;
  88. private Button mButton;
  89. @Override
  90. protected void onCreate(Bundle savedInstanceState) {
  91. super.onCreate(savedInstanceState);
  92. setContentView(R.layout.activity_main);
  93. mButton = (Button) findViewById(R.id.send_message_id);
  94. mButton.setOnClickListener(new View.OnClickListener() {
  95. @Override
  96. public void onClick(View v) {
  97. new ChildThread2("ChildThread2").start();
  98. }
  99. });
  100. new ChildThread1("ChildThread1").start();
  101. }
  102. class ChildThread1 extends Thread {
  103. public ChildThread1(String threadName) {
  104. super(threadName);
  105. }
  106. public void run() {
  107. Looper.prepare();/** init Looper */
  108. handler = new ThreadHandler(Looper.myLooper());
  109. Looper.loop(); /** start Looper */
  110. }
  111. class ThreadHandler extends Handler {
  112. public ThreadHandler(Looper looper) {
  113. super(looper);
  114. }
  115. public void handleMessage(Message msg) {
  116. Log.d("vae_tag", "receive message: " + msg.obj);
  117. }
  118. }
  119. }
  120. class ChildThread2 extends Thread {
  121. public ChildThread2(String threadName) {
  122. super(threadName);
  123. }
  124. public void run() {
  125. Message msg = handler.obtainMessage(1, 1, 1, "child thread send the message");
  126. handler.sendMessage(msg);
  127. }
  128. }

代码都是非常简单的代码,主要抓住Handler往哪个线程发就绑定到对应线程的Looper。
注:关于Message对象,虽然我们可以自己创建一个新的Message,但是更加推荐的是调用handler的obtainMessage方法来获取一个Message对象。这个方法的作用是从系统的消息池中取出一个Message,这样就可以避免Message创建和销毁带来的资源浪费了

五,子线程更新UI的几种方式

  • handler:上面讲过。
  • Activity.runOnUIThread(Runnable):简单代码实现。

    private Button mButton;

    1. private TextView mTextView;
    2. private Activity mActivity;
    3. @Override
    4. protected void onCreate(Bundle savedInstanceState) {
    5. super.onCreate(savedInstanceState);
    6. setContentView(R.layout.activity_main);
    7. mActivity = this;
    8. mTextView = (TextView) findViewById(R.id.text_view_id);
    9. mButton = (Button) findViewById(R.id.send_message_id);
    10. mButton.setOnClickListener(new View.OnClickListener() {
    11. @Override
    12. public void onClick(View v) {
    13. new Thread(){
    14. public void run() {
    15. mActivity.runOnUiThread(new Runnable() {
    16. @Override
    17. public void run() {
    18. mTextView.setText("click ite");
    19. }
    20. });
    21. };
    22. }.start();
    23. }
    24. });
    25. }
  • View.Post(Runnable)或者View.PostDelayed(Runnabe,long)或者handler.post(new Runnable())三个是一个意思实际上是一样的View.Post(Runnable)源码里面会先获取到当前线程的handler,然后再调用post方法(ViewRootImpl.getRunQueue().post(action);):简单代码如下:

    private Button mButton;

    1. private TextView mTextView;
    2. @Override
    3. protected void onCreate(Bundle savedInstanceState) {
    4. super.onCreate(savedInstanceState);
    5. setContentView(R.layout.activity_main);
    6. mTextView = (TextView) findViewById(R.id.text_view_id);
    7. mButton = (Button) findViewById(R.id.send_message_id);
    8. mButton.setOnClickListener(new View.OnClickListener() {
    9. @Override
    10. public void onClick(View v) {
    11. new ChileThread(mButton).start();
    12. }
    13. });
    14. }
    15. public class ChileThread extends Thread {
    16. private Button mButton;
    17. public ChileThread(Button textView) {
    18. mButton = textView;
    19. }
    20. @Override
    21. public void run() {
    22. mButton.post(new Runnable() {
    23. @Override
    24. public void run() {
    25. mTextView.setText("click ite");
    26. }
    27. });
    28. }
    29. }

在这里不管是mButton.post() 还是mTextView.post()都是可以的只要是继承View的对象就行。
- AsyncTask:异步任务,主要是四个重要的方法。

  • onPreExecute:运行在UI线程,主要目的是为后台线程的运行做准备。当他运行完成后,他会调用doInBackground方法。
  • doInBackground:运行在后台线程,他用来负责运行任务。他拥有参数Params,并且返回Result。在后台线程的运行当中,为了能够更新作业完成的进度,需要在doInbackground方法中调用PublishProgress方法。该方法拥有参数Progress。通过该方法可以更新Progress的数据。然后当调用完PublishProgress方法,他会调用onProgressUpdate方法用于更新进度。
  • onProgressUpdate:运行在UI线程,主要目的是用来更新UI线程中显示进度的UI控件。他拥有Progress参数。在doInBackground中调用PublishProgress之后,就会自动调onProgressUpdate方法。
  • onPostExecute:运行在UI线程,当doInBackground方法运行完后,他会调用onPostExecute方法,并传入Result。在onPostExecute方法中,就可以将Result更新到UI控件上。

六,HandlerThread

  1. 我们都知道AndroidHandler的使用,一般都在UI主线程中执行,因此在Handler接收消息后,处理消息时,不能做一些很耗时的操作,否则将出现ANR错误。Android中专门提供了HandlerThread类,来解决该类问题。HandlerThread类是一个线程专门处理Hanlder的消息HandlerThread用于方便的创建一个含有Looper的线程类。Looper用来创建Handler类,实际上就一个Thread,只不过它比普通的Thread多了一个Looper。一般HandlerThreadHandler类配合使用, Handler将消息发往HandlerThread的消息队列, Handler处理消息。这里启动的是一个新线程 虽然不能直接操作UI 但可以通过Message发送消息来进行操作,其实就是把Handler里面要做的比较耗时的操作放到HandlerThread里面去做,如果有必要的话HandlerThread处理完之后可以再发回给UI线程。

使用HandlerThread的好处:

  1. 开发中如果多次使用类似new Thread(){…}.start()这种方式开启一个子线程,会创建多个匿名线程,使得程序运行起来越来越慢,而HandlerThread自带Looper使他可以通过消息来多次重复使用当前线程,节省开支。
  2. android系统提供的Handler类内部的Looper默认绑定的是UI线程的消息队列,对于非UI线程又想使用消息机制,那么HandlerThread内部的Looper是最合适的,它不会干扰或阻塞UI线程。
    简单的实例代码如下:

    public class MainActivity extends ActionBarActivity {

    1. private Handler mHandler;
    2. private MyHandlerThread mHandlerThread;
    3. private Button mButton;
    4. @Override
    5. protected void onCreate(Bundle savedInstanceState) {
    6. super.onCreate(savedInstanceState);
    7. setContentView(R.layout.activity_main);
    8. mHandlerThread = new MyHandlerThread("MyHandlerThread");
    9. mHandlerThread.start();
    10. mHandler = new Handler(mHandlerThread.getLooper(), mHandlerThread);
    11. mButton = (Button) findViewById(R.id.send_message_id);
    12. mButton.setOnClickListener(new View.OnClickListener() {
    13. @Override
    14. public void onClick(View v) {
    15. mHandler.sendEmptyMessage(1);
    16. }
    17. });
    18. }
    19. @Override
    20. protected void onDestroy() {
    21. super.onDestroy();
    22. mHandlerThread.quit();
    23. }
    24. public class MyHandlerThread extends HandlerThread implements Handler.Callback {
    25. public MyHandlerThread(String name) {
    26. super(name);
    27. }
    28. @Override
    29. public boolean handleMessage(Message msg) {
    30. Log.d("vae_tag", "get message");
    31. return true;
    32. }
    33. }

    }

七,线程池

  1. 对应数据库连接我们有数据库连接池,对于线程我们也有线程池。线程池是预先创建线程的一种技术。线程池在任务还没到来之前先创建一定数量的线程,放入空闲队列中。这些线程都是处于睡眠状态,即均为启动,不消耗CPU,而只是占用较小的内存空间。当请求到来之后,缓冲池给这次请求分配一个空闲线程,把请求传入此线程中运行,进行处理。当预先创建的线程都处于运行状态,即预制线程不够,线程池可以自由创建一定数量的新线程,用于处理更多的请求。当系统比较闲的时候,也可以通过移除一部分一直处于停用状态的线程。从而达到减少了创建和销毁线程的次数,最大程度的复用对象。

包括三种单一线程池,固定线程池,缓存的线程池使用其他也非常的简单。
下面是固定线程池的简单实例,很简单的例子。

  1. private Button mButton;
  2. private ExecutorService mExecutorService;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. /** create three threads in the pool */
  8. mExecutorService = Executors.newFixedThreadPool(3);
  9. mExecutorService.submit(new ChileThread("ChileThread"));
  10. mButton = (Button) findViewById(R.id.send_message_id);
  11. mButton.setOnClickListener(new View.OnClickListener() {
  12. @Override
  13. public void onClick(View v) {
  14. mExecutorService.submit(new ChileThread("ChileThread"));
  15. }
  16. });
  17. }
  18. public class ChileThread extends Thread {
  19. public ChileThread(String threadName) {
  20. super(threadName);
  21. }
  22. @Override
  23. public void run() {
  24. Log.d("vae_tag", "aaaaaaaaaaaaaaaaa");
  25. }
  26. }

缓存的线程池 线程池的大小会根据执行的任务数动态分配

  1. mExecutorService = Executors.newCachedThreadPool();

单一线程池

  1. mExecutorService = Executors.newSingleThreadExecutor();

八,Callable,Future

Callable 源码

  1. public interface Callable<V> {
  2. /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */
  3. V call() throws Exception;
  4. }

Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其他线程执行的任务。Callable是一个泛型接口。call()函数返回的类型就是传递进来的V类型,Callable要配合ExecutorService来使用,采用ExecutorService的submit方法提交。
Callable 和 Runnable方法的区别:
1)Callable定义的方法是call,而Runnable定义的方法是run。
2)Callable的call方法可以有返回值,而Runnable的run方法不能有返回值。
3)Callable的call方法可抛出异常,而Runnable的run方法不能抛出异常。

Future表示异步计算的结果,它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。Future的cancel方法可以取消任务的执行,它有一布尔参数,参数为 true 表示立即中断任务的执行,参数为 false 表示允许正在运行的任务运行完成。Future的 get 方法等待计算完成,获取计算结果。简单的实例代码如下。

  1. 单个任务:

    public class MainActivity extends ActionBarActivity {

    1. @Override
    2. protected void onCreate(Bundle savedInstanceState) {
    3. super.onCreate(savedInstanceState);
    4. setContentView(R.layout.activity_main);
    5. signalTaskTest();
    6. Log.d("vae_tag", "after signalTaskTest function");
    7. }
    8. private void signalTaskTest() {
    9. Task.callInBackground(new Callable<Void>() {
    10. @Override
    11. public Void call() throws Exception {
    12. /** start test */
    13. ExecutorService threadPool = Executors.newSingleThreadExecutor();
    14. Future<String> future = threadPool.submit(new Callable<String>() {
    15. public String call() throws Exception {
    16. Thread.sleep(2000);
    17. return "hello";
    18. }
    19. });
    20. Log.d("vae_tag", "start waiting result");
    21. try {
    22. Log.d("vae_tag", "get the result " + future.get());
    23. } catch (InterruptedException e) {
    24. // TODO Auto-generated catch block
    25. e.printStackTrace();
    26. } catch (ExecutionException e) {
    27. // TODO Auto-generated catch block
    28. e.printStackTrace();
    29. }
    30. return null;
    31. }
    32. });
    33. }

    }

注:我是在一个线程里面测试 future.get()会等待获取结果(这里有用到Task.callInBackground 在gradle用引入compile ‘com.parse.bolts:bolts-android:1.2.0’)

  1. 多个任务:

    public class MainActivity extends ActionBarActivity {

    1. @Override
    2. protected void onCreate(Bundle savedInstanceState) {
    3. super.onCreate(savedInstanceState);
    4. setContentView(R.layout.activity_main);
    5. multipleTasksTest();
    6. }
    7. private void multipleTasksTest() {
    8. Task.callInBackground(new Callable<Void>() {
    9. @Override
    10. public Void call() throws Exception {
    11. /** start test */
    12. ExecutorService threadPool2 = Executors.newFixedThreadPool(10);
    13. CompletionService<Integer> compeletionService = new ExecutorCompletionService<Integer>(
    14. threadPool2);
    15. for (int i = 0; i <= 10; i++) {
    16. final int seq = i;
    17. compeletionService.submit(new Callable<Integer>() {
    18. @Override
    19. public Integer call() throws Exception {
    20. Thread.sleep(new Random().nextInt(5000));
    21. return seq;
    22. }
    23. });
    24. }
    25. for (int i = 0; i < 10; i++) {
    26. try {
    27. Log.d("vae_tag", "result = " + compeletionService.take().get());
    28. } catch (InterruptedException e) {
    29. // TODO Auto-generated catch block
    30. e.printStackTrace();
    31. } catch (ExecutionException e) {
    32. // TODO Auto-generated catch block
    33. e.printStackTrace();
    34. }
    35. }
    36. return null;
    37. }
    38. });
    39. }

    }

配合CompletionService使用。

九,推荐(EventBus 一个可以用于通信的开源库)

github项目地址 https://github.com/greenrobot/EventBus

这个也是我们在应用中经常用到的用于通信的一个类库。特别是在fragment 和fragment,fragment和activity等等之间通信非常的方便,用起来也非常的简单具体的可以去google下。

发表评论

表情:
评论列表 (有 0 条评论,249人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Thread线

    目录 需要笔记的可以关注私聊我发给你 Thread 线程的创建方式 方式一(继承Thread类方式) 方式二(实现Runnable方式) 方式三(实现Callab

    相关 Android Thread线

           相信大家对线程肯定不陌生,我们在编程的过程中经常要用到线程,Android提供了多线程支持,在Android程序中,VM采用抢占式调度模式对线程进行调度(基于线程

    相关 线--继承Thread

    首先继承Thread类,然后重写Thread类的run()方法。 Thread类的子类的对象调用start()方法,然后虚拟机就会调用该线程的run()方法。 当程序执行到

    相关 线Thread

    -------------------- \\java中的线程分类 User Thread 用户线程 运行在前台,执行具体任务: 比如程序的主线程、连接网络的子线程等等

    相关 线-Thread

    线程 线程和进程的区别: ①线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。