文档章节

Android线程相关

max0x99
 max0x99
发布于 2016/01/23 17:14
字数 1686
阅读 31
收藏 0

    线程是的概念;

    线程是用来做什么;

    如何使用线程;

    首先说概念:线程,有时被称之为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。

    我们都知道,每一个Android应用都在自己的进程中执行,每一个进程都可以有多条线程存在执行。我们在开启一个APP的时候,首先我们知道主线程,也就是UI主线程;在主线程中用来处理UI界面刷新的一些操作,我们不能再主线程做一些耗时的操作,因为耗时操作会导致主线程堵塞,Activity 的最长时间是 5S 堵塞的超出了限定的时候从而报错ANR(Application Not Responding)即使是 BrodcastReceiver最长的执行也是10S,所以也不能做耗时的操作;当主线程不能做耗时操作的时候我们就需要另起线程来缓解主线程的压力;那么结果来了,我们使用多线程是为了让APP运行更加流畅,缓解主线程的压力;

    下面看一张图1,说明了线程中执行的过程:

 调用线程的start方法后线程进入就绪状态,线程调度系统将就绪状态的线程转为运行状态,遇到synchronized语句时,由运行状态转为堵塞,当synchronized获取锁后,由堵塞转为运行,在这种情况下可以调用wait方法转为挂起状态,当线程关联的代码执行完成后,线程变为结束状态。

第三点,我们要怎么使用多线程:这里是重点,

方式1: new Thread 重写run方法,然后start既可以,如下代码:

new Thread(){
    public void run(){
        try{
            for(int i = 0; i< 10; i++){
                Logger.debug(TAG,"testThread--" + i);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}.start();

方式2:实现runnable接口,new Thread(new Runnable()).start()

new Thread(new Runnable() {
    @Override
    public void run() {
        try{
            for(int i = 0; i< 10; i++){
                Logger.debug(TAG,"testThread2--" + i);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}).start();

方式3:使用Android 提供的异步类:

new MyAsycTask().execute();
private class MyAsycTask extends AsyncTask{
    public MyAsycTask() {
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        Logger.debug(TAG,"主线程执行,提醒用户我要执行某项操作了。");
    }

    @Override
    protected Object doInBackground(Object[] params) {
        Logger.debug(TAG,"子线程执行,提醒用户我努力运算。");
        return null;
    }

    @Override
    protected void onPostExecute(Object o) {
        super.onPostExecute(o);
        Logger.debug(TAG, "主线程执行,提醒用户我已经运算完成并且返回了结果。");
    }

    @Override
    protected void onProgressUpdate(Object[] values) {
        super.onProgressUpdate(values);
        Logger.debug(TAG, "主线程执行,提醒用户你可以跟新某某某");
    }

    @Override
    protected void onCancelled(Object o) {
        super.onCancelled(o);
    }

    @Override
    protected void onCancelled() {
        super.onCancelled();
    }
}

    在AsyncTask这里有必要多写一点,首先明确,AsyncTask是封装好的线程池,比起Handler+Thread 的方式更加方便。那么在2.3以前的版本里面,AsyncTask的封装同时运行线程个数是5,加入你的后台需要超过五个的线程,那么使用AsyncTask就需要这五个执行完成后在进行第六个执行,如果这五个的执行时候超长,第六个就会等很长时间。所以这种情况使用AsyncTask是十分不便了。

    在Android3.0以后,Google也意识到这个问题,在3.0以后对API做出了调整,按照execute()提交顺序,每次执行一个任务,等待上个任务执行完成下个任务在进行,也就类似于Eexcutors.newSingleThreadPool()。我的天啊,AsyncTask执行任务按照提交顺序逐个运行,不能忍!还好在API里面提供了executeOnExecutor(ExecutorService)使用自定义的线程池进行任务的运行和调度,同时把自定义线程池交给AsyncTask运行即可;

    Java通过Executors提供的四种线程池,分别是:

    newcachedThreadPool;//创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程;

    newFixedThreadPool;//创建一个定长线程池,可控制线程最大并发数,超出线程会队列中等待;

    newScheduleThreadPool;//创建一个定长线程池,支持定时及周期性任务执行;

    newSingleThreExecutor;//创建一个单线程化线程池,它只会用唯一的工作线程来执行任务,保证所有的任务指定顺序(FIFO,LIFO,优先级);

myAsyncTask.executeOnExecutor()

   上面代码是AsyncTask如何调用自定义线程池;

 

方式4:抛弃AsyncTask使用自定义线程池,这里也是离不开java API的线程池:

Executors.newSingleThreadExecutor().execute(new MyRunnable(""));
Executors.newCachedThreadPool().execute(new MyRunnable(""));
Executors.newCachedThreadPool().execute(new MyRunnable(""));
Executors.newFixedThreadPool(count).execute(new MyRunnable(""));

 

线程的开销是非常大的,同时异步处理也容易出错,难调试,难维护,所以改善你的设计,尽可能的少用异步。对于一般性的数据库查询,少量的I/O操作是没有必要启动线程的。
•与主线程有交互时用AsyncTask,否则就用Thread
AsyncTask被设计出来的目的就是为了满足Android的特殊需求:非主线程不能操作(UI)组件,所以AsyncTask扩展Thread增强了与主线程的交互的能力。如果你的应用没有与主线程交互,那么就直接使用Thread就好了。
•当有需要大量线程执行任务时,一定要创建线程池
线程的开销是非常大的,特别是创建一个新线程,否则就不必设计线程池之类的工具了。当需要大量线程执行任务时,一定要创建线程池,无论是使用AsyncTask还是Thread,因为使用AsyncTask它内部的线程池有数量限制,可能无法满足需求;使用Thread更是要线程池来管理,避免虚拟机创建大量的线程。比如从网络上批量下载图片,你不想一个一个的下,或者5个5个的下载,那么就创建一个CorePoolSize为10或者20的线程池,每次10个或者20个这样的下载,即满足了速度,又不至于耗费无用的性能开销去无限制的创建线程。
•对于想要立即开始执行的异步任务,要么直接使用Thread,要么单独创建线程池提供给AsyncTask
默认的AsyncTask不一定会立即执行你的任务,除非你提供给他一个单独的线程池。如果不与主线程交互,直接创建一个Thread就可以了,虽然创建线程开销比较大,但如果这不是批量操作就没有问题。

© 著作权归作者所有

max0x99
粉丝 1
博文 2
码字总数 3199
作品 0
朝阳
程序员
私信 提问
Android多线程:这是一份全面 & 详细的HandlerThread学习指南

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的机制的学习指南,内容包括:定性认知、定量使用、工作原理 & 源码分析,希望你们会喜欢。...

Carson_Ho
05/16
0
0
Thread和Looper以及Handler和Message详解 Android开发必读

很多初入Android或Java开发的新手对Thread、Looper、Handler和Message仍然比较迷惑,衍生的有HandlerThread、java.util.concurrent、Task、AsyncTask由于目前市面上的书籍等资料都没有谈到这...

元来元去
2011/11/28
0
0
Android之Handler用法总结

方法一:(java习惯,在android平台开发时这样是不行的,因为它违背了单线程模型) 刚刚开始接触android线程编程的时候,习惯好像java一样,试图用下面的代码解决问题 Thread( Runnable() { r...

霞女
2014/04/16
0
0
android基础知识02——线程安全1:定义及例子

android的UI操作不是线程安全的,同时也只有主线程才能够操作UI,同时主线程对于UI操作有一定的时间限制(最长5秒)。为了能够做一些比较耗时的操作(比如下载、打开大文件等),android提供...

迷途d书童
2012/03/23
793
0
Android之Handler用法总结

Android之Handler用法总结 方法一:(java习惯,在android平台开发时这样是不行的,因为它违背了单线程模型) 刚刚开始接触android线程编程的时候,习惯好像java一样,试图用下面的代码解决问...

crystaltiger
2013/08/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Cloud中Hystrix 线程隔离导致ThreadLocal数据丢失

在Spring Cloud中我们用Hystrix来实现断路器,Zuul中默认是用信号量(Hystrix默认是线程)来进行隔离的,我们可以通过配置使用线程方式隔离。 在使用线程隔离的时候,有个问题是必须要解决的...

xiaomin0322
35分钟前
1
0
使用 Jenkins + Ansible 实现 Spring Boot 自动化部署101

本文首发于:Jenkins 中文社区 本文要点: 设计一条 Spring Boot 最基本的流水线:包括构建、制品上传、部署。 使用 Docker 容器运行构建逻辑。 自动化整个实验环境:包括 Jenkins 的配置,J...

Jenkins中文社区
39分钟前
1
0
springcloud配置中心和消息总线,学习,记录其中的问题

改造配置中心的客户端,接入消息总线 1.增加pom文件的引用 <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20......

夜中孤影
52分钟前
3
0
gzip压缩

tar -zcvf gz包路径 被压缩的路径 tar -zcvf /home/xxx/test.tar.gz hello gz包的路径可以是 完整的也可以相对 , 被压缩的路径 不要全路径 不然压缩包里也会有全路径...

shzwork
58分钟前
3
0
rancher-1

部署rancher 官方快速部署 https://www.cnrancher.com/quick-start/ 部署命令 mkdir /data/rancher -p# 建立存放rancher数据的目录sudo docker run -d --restart=unless-stopped -v /dat......

以谁为师
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部