热门IT资讯网

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

发表于:2024-11-28 作者:热门IT资讯网编辑
编辑最后更新 2024年11月28日,刚开始学一门编程语言的时候,我总是会有一种困惑,怎样让自己的代码看起来更"专业"?很多时候,我们可以照着教材实现一些基本的功能,比如用Socket发送/接收几个字符,写一个线程完成某个异步任务,但是在

刚开始学一门编程语言的时候,我总是会有一种困惑,怎样让自己的代码看起来更"专业"?很多时候,我们可以照着教材实现一些基本的功能,比如用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,因此,现在格外注意这一点,而且习惯性在线程结束的地方打印出调试信息,以保证程序中开启的所有线程都正常地销毁了。


关于线程的处理就分享到这里啦,希望对初学者有帮助,有任何疑问欢迎留言或者来信[email protected]交流。


附件:http://down.51cto.com/data/2364424
0