Android开发实践:以“专业”的态度处理多线程
刚开始学一门编程语言的时候,我总是会有一种困惑,怎样让自己的代码看起来更“专业”?很多时候,我们可以照着教材实现一些基本的功能,比如用Socket发送/接收几个字符,写一个线程完成某个异步任务,但是在实际的项目中,往往不那么简单,比如需要设计Socket通信协议,需要处理Socket的连接异常断开,需要考虑在线程阻塞的情况下如何正常退出和释放资源等等,关于这些“实战经验”,前面的文章也有所涉及,以后有空准备再开个专题跟大家分享探讨一下,今天先简单地说说怎样更“专业”地在Android程序中处理多线程。
下面假设实现一个简单的定时任务,每秒钟打印一条Log信息,看看实现这样一个多线程程序,有哪些需要注意的地方,关键点都以注释的形式添加到代码中了。
package com.ticktick.testthread; import android.util.Log; public class PrintThread implements Runnable { private Thread mThread; private boolean mIsThreadStarted = false; private volatile boolean mIsThreadExit = false; //关键1:定义一个volatile类型的条件变量,用于线程的退出 public void startPrintThread() { if( mIsThreadStarted ) { return; } mIsThreadExit = false; mThread = new Thread(this); //关键2:每次启动都重新创建新的Thread对象,因为一个Thread只能被start一次 mThread.start(); mIsThreadStarted = true; Log.d("PrintThread", "Timer Started"); } public void stopPrintThread() { if( !mIsThreadStarted ) { return; } mIsThreadExit = true; //关键3:通知线程退出循环 mThread.interrupt(); //关键4:调用interrupt,防止线程内部处于sleep或者wait等阻塞状态 //不过注意,对于socket.accept这样的阻塞,thread.interrupt是没有办法的,但可以用socket.close来唤醒 try { mThread.join(1000); //关键5:调用join,等待线程真正地完成退出,建议给出一个等待超时时间 } catch (InterruptedException e) { e.printStackTrace(); } mIsThreadStarted = false; Log.d("PrintThread", "Thread Stopped"); } public boolean isThreadStarted() { return mIsThreadStarted; } @Override public void run() { Log.d("PrintThread", "Thread Run Enter !"); while( !mIsThreadExit ) { Log.d("PrintThread", "Thread Arrived !"); try { Thread.sleep(1000); //关键6:线程循环中,建议使用sleep,让其他线程可以竞争CPU,sleep(0)代表立即重新竞争一次CPU } catch (InterruptedException e) { e.printStackTrace(); //这里可以直接跳出循环,也可以忽略它而再次检查条件变量 mIsThreadExit } } Log.d("PrintThread", "Thread Run Exit !"); } }
其实,不仅是Java线程,C/C++的多线程也应该注意这几个关键点,这里再总结一下:
(1)要定义一个volatile类型的条件变量,决定是否退出线程的死循环
(2)线程循环中,最好有sleep延时函数,让其他线程有机会竞争CPU
(3)要停止线程执行,需要做三件事,1. 置位线程退出的条件变量;2. 通过类似interrupt或者socket.close 的调用,唤醒线程中的阻塞;3. 通过join函数,等待线程真正退出,然后再释放其他相关资源
曾经在项目中,没有通过join等待线程退出,导致经常会在软件退出的时候莫名其妙地crash,因此,现在格外注意这一点,而且习惯性在线程结束的地方打印出调试信息,以保证程序中开启的所有线程都正常地销毁了。
关于线程的处理就分享到这里啦,希望对初学者有帮助,有任何疑问欢迎留言或者来信lujun.hust@gmail.com交流。
本文出自 “对影成三人” 博客,请务必保留此出处http://ticktick.blog.51cto.com/823160/1410697