今天在这篇博客里面,我只想谈谈自己对程序开发里面避无可避的一个问题-多线程的一些看法与思考。

其实说到多线程这个名称相信只要接触过软件这个行业的人都已经耳熟能详了,但是如果被问到到底什么才是多线程呢?为什么我们会需要多线程呢?多线程又会造成什么副作用呢?其实这些都应该是值得我们深入思考的一些问题,因为在多线程的环境里面,往往会发生一些意想不到的事情。下面让我们来针对android平台来具体看看多线程应该是怎么一回事呢?其实在android里面,系统已经为我们提供了一些封装好的多线程api,比如runable接口,AsyncTask后台任务等。

让我们先来看看一段代码,这段代码是比较常规的创建、开启一个线程的方法。

public class TestThread extends Thread {@Overridepublic void run() {//do your something}
}

上面方法只是定义好了一个线程,然后我们应该调用下面的方法运营它。

private void runMyThread(){new TestThread().start();
}

这样的话,我们就相当于已经开启了一个线程。所以只要不手动中断这个线程的话,那么该线程就会在App处于运行态时一直跑。所以这个时候,如果我们有什么比较耗时的操作的话,我们就可以放在run方法里面执行了。下面就让我们来看看Thread里面的源码,看看为什么Thread调用start方法就会运行,为什么每个线程开启之后都会循环执行里面的run方法呢?有没有什么办法去中断一个线程呢?

首先我们来看看Thread的类定义,如下:

public class Thread implements Runnable{
}

可以看到Thread其实也是从Runable继承而来,那么什么是Runable呢?让我们稍后讲。一进到Thread类定义里面,给我们最直观的感受就是“volatile”,“ThreadLocal”,还有各种的Thread构造方法。我们可以看到在每个Thread构造方法里面都调用了create方法,相信看到这个名字大家就应该能够知道它是干什么用的吧,让我们截出create的源码来看看:

private void create(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {Thread currentThread = Thread.currentThread();if (group == null) {group = currentThread.getThreadGroup();}if (group.isDestroyed()) {throw new IllegalThreadStateException("Group already destroyed");}this.group = group;synchronized (Thread.class) {id = ++Thread.count;}if (threadName == null) {this.name = "Thread-" + id;} else {this.name = threadName;}this.target = runnable;this.stackSize = stackSize;this.priority = currentThread.getPriority();this.contextClassLoader = currentThread.contextClassLoader;// Transfer over InheritableThreadLocals.if (currentThread.inheritableValues != null) {inheritableValues = new ThreadLocal.Values(currentThread.inheritableValues);}// add ourselves to our ThreadGroup of choicethis.group.addThread(this);}

从上面的源码我们可以很清楚的看到create方法里面就是设置线程所属的ThreadGroup,ThreadName,StackSize,但是有一点需要特别注意就是Runable对象,它是用来干什么的呢?我们通过代码查找,发现它主要是用在run方法里面,代码如下:

public void run() {if (target != null) {target.run();}}

我们可以看到Thread里面的run方法,其实是调用了Runable里面的方法。也就是说你可以在Thread实例化的时候,传进来一个Runable对象,这个时候就能执行到里面的run方法了。但是别急,如果你以为这样就能够真正创建一个线程的话,那么就错了。我们可以再看看start方法,也许你就能够明白了。

public synchronized void start() {checkNotStarted();hasBeenStarted = true;nativeCreate(this, stackSize, daemon);}private native static void nativeCreate(Thread t, long stackSize, boolean daemon);

看到了吗?其实在nativeCreate方法里面才会利用create方法里面设置的参数进行真正进行创建过程。现在让我们回到原来那个问题上,为什么线程创建之后,会一直执行run方法呢?具体怎么循环调用的,我在源码里面没有找到,也许是在c层调的吧。然后我们还可以看到常用的sleep方法,源码如下:

public static void sleep(long millis, int nanos) throws InterruptedException {if (millis < 0) {throw new IllegalArgumentException("millis < 0: " + millis);}if (nanos < 0) {throw new IllegalArgumentException("nanos < 0: " + nanos);}if (nanos > 999999) {throw new IllegalArgumentException("nanos > 999999: " + nanos);}// The JLS 3rd edition, section 17.9 says: "...sleep for zero// time...need not have observable effects."if (millis == 0 && nanos == 0) {// ...but we still have to handle being interrupted.if (Thread.interrupted()) {throw new InterruptedException();}return;}long start = System.nanoTime();long duration = (millis * NANOS_PER_MILLI) + nanos;Object lock = currentThread().lock;// Wait may return early, so loop until sleep duration passes.synchronized (lock) {while (true) {sleep(lock, millis, nanos);long now = System.nanoTime();long elapsed = now - start;if (elapsed >= duration) {break;}duration -= elapsed;start = now;millis = duration / NANOS_PER_MILLI;nanos = (int) (duration % NANOS_PER_MILLI);}}}

我们可以看到在java这层只是做了一些时间上面的预设判断,真正的sleep实现是调用c层代码:

private static native void sleep(Object lock, long millis, int nanos);

最后让我们再来看看线程中断的方法:

public void interrupt() {// Interrupt this thread before running actions so that other// threads that observe the interrupt as a result of an action// will see that this thread is in the interrupted state.nativeInterrupt();synchronized (interruptActions) {for (int i = interruptActions.size() - 1; i >= 0; i--) {interruptActions.get(i).run();}}}private native void nativeInterrupt();

看到上面的代码其实有一点不解的就是,是不是意味着我中断当前的一个线程,系统就会默认启动后一个线程呢?

好了,接下来我们可以再看看Runable,其实可以发现它就是一个接口,里面提供了一个run方法,代码如下:

public interface Runnable {/*** Starts executing the active part of the class' code. This method is* called when a thread is started that has been created with a class which* implements {@code Runnable}.*/public void run();
}

最后我们来看看AsyncTask方法,它的特点是什么?我们应该怎么来使用它呢?首先我们来看看在android代码里面通常的使用方法是:

public class TestAsyncTask extends AsyncTask<String,Object,String> {@Overrideprotected String doInBackground(String... params) {return null;}@Overrideprotected void onPostExecute(String s) {super.onPostExecute(s);}@Overrideprotected void onProgressUpdate(Object... values) {super.onProgressUpdate(values);}
}

定义一个类,然后继承AsyncTask复写里面的三个方法。下面就让我们来具体看看AsyncTask的类定义:

public abstract class AsyncTask<Params, Progress, Result> {
}

我们可以看到AsyncTask是一个抽象类,同时利用泛型的方式定义三个参数,分别代表传入的参数、执行过程的进度、执行之后的结果。那么在AsyncTask里面又是怎样调用doInBackground方法的呢?这就要回想一下,当我们定义好一个AsyncTask的时候,是怎样运行它的呢?代码如下:

private void testMyAsyncTask(){new TestAsyncTask().execute(url);
}

所以我们只要看看execute方法里面是不是有调用就知道了。

@MainThreadpublic final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {if (mStatus != Status.PENDING) {switch (mStatus) {case RUNNING:throw new IllegalStateException("Cannot execute task:"+ " the task is already running.");case FINISHED:throw new IllegalStateException("Cannot execute task:"+ " the task has already been executed "+ "(a task can be executed only once)");}}mStatus = Status.RUNNING;onPreExecute();mWorker.mParams = params;exec.execute(mFuture);return this;}

最终它会调用到上面的方法实现我们复写的三个方法实现。

好了,这篇博客就到这里。理解不够深入、不到的地方,欢迎拍砖!

转载于:https://www.cnblogs.com/xiaocai20091687/p/android-xiaocai-thread.html

android开发系列之多线程相关推荐

  1. Android开发中的多线程编程技术

    Android开发中的多线程编程技术 [IT168技术]多线程这个令人生畏的"洪水猛兽",很多人谈起多线程都心存畏惧.在Android开发过程中,多线程真的很难吗?多线程程序的&q ...

  2. Android开发系列7——icon图标和开机启动页

    前言   Android开发App过程中,需要一个独特吸引眼球的应用icon,以及标新的Launch页面用于简明的介绍.为了适配各种 手机的尺寸和手机屏幕分辩率,需要同一张图片制作多种尺寸用于兼容各种 ...

  3. 最新网易微专业 Android开发系列

    目录 ├─1.Android应用界面开发 │  ├─001 Android开发简介.flv │  ├─002 开始第一个应用.flv │  ├─003 Activity你必须知道的那些事(上).flv ...

  4. Android 开发中的多线程编程技术

    此文章来自"Intel Software"应用开发 多线程这个令人生畏的"洪水猛兽",很多人谈起多线程都心存畏惧.在Android开发过程中,多线程真的很难吗? ...

  5. Android开发系列全套课程(视频教程50G)

    本系列课程面向有java基础,想进入企业从事android开发的计算机专业者.学习搭配实战案例,高效掌握岗位知识. 原来地址失效 链接已更新(2021年5月1号更新): https://pan.bai ...

  6. Android开发系列(三)

    这是更加android开发文档,写的我的第一个Android开发项目,就是在屏幕上显示一个简单的Hello World.       首先介绍几个概念:       AVD,AVD的全称为:Andro ...

  7. 零基础学Android开发系列

    目标:沉浸了这么久,准备写点文章,在写文章的同时,巩固Android开发的基础知识,每天一个Android小案例,从零带领大家开发简单的Android应用.

  8. Android开发系列——实战篇11:多线程与异步机制

    本文介绍安卓的多线程与异步任务处理的机制 目录 一.多线程 1.主线程与子线程 2.Handler用法详解 使用Handler发送post请求 使用Handler处理Message消息 一.多线程 1 ...

  9. Android开发系列(十二) QQ联系人列表升级版——ListView和ScrollView高阶使用方法...

    今天继续进行QQ界面的开发工作.前一段时间讲过ExpandableListView的使用并且设置了一个比较简单的具有子菜单效果的联系人列表,本节添加进ScrollView控件,对QQ2013版的联系人 ...

最新文章

  1. 解决Eclipse代码分析插件SonarLint在Console输出乱码问题
  2. poj 3258 River Hopscotch 【二分】
  3. 线程安全和对应的核心概念
  4. ES6技巧和窍门,使您的代码更简洁,更短且更易于阅读!
  5. 基于JAVA+SpringBoot+Mybatis+MYSQL的校园新闻管理系统
  6. 实践总结 - 不可错过的Angular应用技巧
  7. 腾讯首发汽车解决方案 助力广汽打造新智能网联云平台
  8. Neo4j下载与安装
  9. Oracle PLM,协同研发的产品生命周期管理平台
  10. 计量经济学(三)--假设检验
  11. ERP管理系统如何与精益生产MES有效结合
  12. Autovue Client/Server 性能优化
  13. 微积分的历史(五):发展之泰勒公式(上)
  14. host文件是干嘛的?有什么用?
  15. 通过“microbenchmark”解谜GPU的微架构
  16. vue3【列表渲染】v-for 详细介绍(vue中的“循环”)
  17. 计算机设置从光盘启动怎么办,如何设置光盘启动计算机
  18. 16-3d和盒阴影和遮罩
  19. 畅通工程 hdu 1232 HDU - 1863 (并查集+最小生成树)
  20. 2022年全国大学生数学建模竞赛A题思路

热门文章

  1. 查看源代码不方便?我有利器
  2. sqlserver创建存储过程、函数、
  3. 再谈无边框窗体的操作
  4. django时间格式化加时区控制
  5. BZOJ1563:[NOI2009]诗人小G(决策单调性DP)
  6. onMeasure模式
  7. Java集合类解析 ***
  8. maven项目编译漏掉src/main/java下的xml配置文件
  9. eclips 的pydev的debug
  10. 一个自己整理的HASH类