Android开发实践:以“专业”的态度处理多线程

   刚开始学一门编程语言的时候,我总是会有一种困惑,怎样让自己的代码看起来更“专业”?很多时候,我们可以照着教材实现一些基本的功能,比如用Socket发送/接收几个字符,写一个线程完成某个异步任务,但是在实际的项目中,往往不那么简单,比如需要设计Socket通信协议,需要处理Socket的连接异常断开,需要考虑在线程阻塞的情况下如何正常退出和释放资源等等,关于这些“实战经验”,前面的文章也有所涉及,以后有空准备再开个专题跟大家分享探讨一下,今天先简单地说说怎样更“专业”地在Android程序中处理多线程。

创新互联公司自2013年创立以来,先为安居等服务建站,安居等地企业,进行企业商务咨询服务。为安居企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。

   下面假设实现一个简单的定时任务,每秒钟打印一条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://down.51cto.com/data/2364424

分享名称:Android开发实践:以“专业”的态度处理多线程
本文URL:http://pwwzsj.com/article/ggehhs.html