目录 1,线程Thread 1.1 Thread概念 1.2 Thread 几种状态 1.3 Thread 主要函数 1.4 Thread 的使用 1.5 Thread 安全与Thread 同步 2,多线程的实现方式 2.1 Handler+Thread github上demo地址 https://github.com/labiqi/android-download 2.2 AsyncTask github上demo地址 https://github.com/labiqi/pdfView 2.3 IntentService 2.4 ThreadPoolExecutor 2.5 RxJava 1 线程Thread 1.1 Thread概念 线程,可以看作是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程可并发执行,并且共享进程资源。 1.2 Thread 几种状态 新建状态(New) 实例化之后进入该状态; 就绪状态(Runnable) 线程调用start()之后就绪状态等待cpu执行,注意这时只是表示可以运行并不代表已经运行;若被线程调度程序调度,这个线程便会成为当前运行(Running)的线程; 阻塞状态(Blocked)线程由于各种原因进入阻塞状态:join()、sleep()、wait()、等待触发条件、等待由别的线程占用的锁;比如若一段代码被线程A”上锁“,此时线程B尝试执行这段代码,线程B就会进入Blocked状态 等待(Waiting) 当线程等待另一个线程通知线程调度器一个条件时,它本身就会进入Waiting状态; 计时等待(Time Waiting) 计时等待与等待的区别是,线程只等待一定的时间,若超时则不再等待; 被终止(Terminated)线程的run方法执行完毕或者由于一个未捕获的异常导致run方法意外终止会进入Terminated状态。
public static enum State { BLOCKED, NEW, RUNNABLE, TERMINATED, TIMED_WAITING, WAITING; private State() { } }1.3 Thread 主要函数 1.4 Thread 的使用 1,继承Thread,重写run()方法,使用时直接new并且start()
public class MyThread extends Thread { @Override public void run() { super.run(); //todo something } } public void startThread() { new MyThread().start(); }2,从上面的方法的源码我们可知,其实Thread运行时是调用了Runnable 接口中的run方法,那么我们可以重新定义一个类实现Runnable 接口中的run方法:但是这种显示创建线程的方法不建议使用。
public class MyRunnable implements Runnable { @Override public void run() { //todo something } } public void startThread() { new Thread(new MyRunnable()).start(); } 也可以使用匿名内部类实现: new Thread(new Runnable() { @Override public void run() { } }).start();3,通过Handler启动线程。
private Handler mHandler = new Handler(); private Runnable runnable = new Runnable() { @Override public void run() { Log.d("当前线程",Thread.currentThread().getName()); btn1.setText("当前线程为ui线程"); } }; findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mHandler.post(runnable); // handler运行runnable } });handler.post®其实这样并不会新起线程,只是执行的runnable里的run()方法,却没有执行start()方法,所以runnable走的还是UI线程。如果像这样,是可以操作ui,但是run还是走在主线程,见打印出来的Log线程名字是main,说明是主线程。 1.5 Thread 安全与Thread 同步 线程安全问题是指多个线程访问同一代码或数据,造成结果和数据的错乱或与期望的结果不同所产生的问题。采用“序列化访问临界资源”的方案,即在同一时刻只能有一个线程访问临界资源(多个线程可能同时访问的数据或资源),也称同步互斥访问。常见的有以下几种方式: 1,synchronized 关键字,保证同时刻只有一个线程进入该方法或者代码块 线程run()方法添加synchronized关键字
public class MyThread extends Thread { @Override public void run() { super.run(); count(); } } private synchronized void count() { //todo something }同步代码块的形式使用
private void count() { if(synchronized (this) { //todo something } }2,特殊域变量volatile修饰变量:告诉虚拟机该变量随时可能更新,因此使用时每次都会重新计算,而不是使用寄存器的值。volatile不会提供任何原子操作,它也不能用来修饰final类型的变量。(不能完全保证线程安全) private volatile int num = 1000; 3,使用重入锁实现线程同步:lock() :获得锁,unlock() : 释放锁。
private void threadRunFunction() { lock.lock(); //todo something lock.unlock(); }2,多线程的实现方式 2.1 Handler+Thread Android主线程包含一个消息队列(MessageQueue),该消息队列里面可以存入一系列的Message或Runnable对象。通过一个Handler你可以往这个消息队列发送Message或者Runnable对象,并且处理这些对象。每次你新创建一个Handle对象,它会绑定于创建它的线程(也就是UI线程)以及该线程的消息队列,从这时起,这个handler就会开始把Message或Runnable对象传递到消息队列中,并在它们出队列的时候执行它们。 优缺点
Handler用法简单明了,可以将多个异步任务更新UI的代码放在一起,清晰明了;处理单个异步任务代码略显多。 适用范围多个异步任务的更新UI。 具体关于Handler的讲解可以看另外一篇博客https://blog.csdn.net/weixin_42042620/article/details/90239713以及github上demo地址 https://github.com/labiqi/android-download。 2.2 AsyncTask AsyncTask是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程。AsyncTask通过一个阻塞队列BlockingQuery存储待执行的任务,利用静态线程池THREAD_POOL_EXECUTOR提供一定数量的线程,默认128个。在Android 3.0以前,默认采取的是并行任务执行器,3.0以后改成了默认采用串行任务执行器,通过静态串行任务执行器SERIAL_EXECUTOR控制任务串行执行,循环取出任务交给THREAD_POOL_EXECUTOR中的线程执行,执行完一个,再执行下一个。 构建AsyncTask子类的泛型参数 AsyncTask<Params,Progress,Result>是一个抽象类,通常用于被继承.继承AsyncTask需要指定如下三个泛型参数: Params:启动任务时输入的参数类型. Progress:后台任务执行中返回进度值的类型. Result:后台任务执行完成后返回结果的类型. 构建AsyncTask子类的回调方法 AsyncTask主要有如下几个方法: doInBackground:必须重写,异步执行后台线程要完成的任务,耗时操作将在此方法中完成. onPreExecute:执行后台耗时操作前被调用,通常用于进行初始化操作. onPostExecute:当doInBackground方法完成后,系统将自动调用此方法,并将doInBackground方法返回的值传入此方法.通过此方法进行UI的更新. onProgressUpdate:当在doInBackground方法中调用publishProgress方法更新任务执行进度后,将调用此方法.通过此方法我们可以知晓任务的完成进度. 使用AsyncTask的注意事项 ① 必须在UI线程中创建AsyncTask的实例. ② 只能在UI线程中调用AsyncTask的execute方法. ③ AsyncTask被重写的四个方法是系统自动调用的,不应手动调用. ④ 每个AsyncTask只能被执行(execute方法)一次,多次执行将会引发异常. ⑤ AsyncTask的四个方法,只有doInBackground方法是运行在其他线程中,其他三个方法都运行在UI线程中,也就说其他三个方法都可以进行UI的更新操作. AsyncTask优缺点 处理单个异步任务简单,可以获取到异步任务的进度; 可以通过cancel方法取消还没执行完的AsyncTask; 处理多个异步任务代码显得较多。 适用范围 单个异步任务的处理。 AsyncTask github上demo地址 https://github.com/labiqi/pdfView 2.3 IntentService IntentService是一个基础类,用于处理Intent类型的异步任务请求。当客户端调用android.content.Context#startService(Intent)发送请求时,Service服务被启动,且在其内部构建一个工作线程来处理Intent请求。当工作线程执行结束,Service服务会自动停止。IntentService是一个抽象类,用户必须实现一个子类去继承它,且必须实现IntentService里面的抽象方法onHandleIntent来处理异步任务请求。查看源码可知: public abstract class IntentService extends Service { private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler; private String mName; private boolean mRedelivery; //搭建一套Handler的处理机制 private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } } ...... /** * This method is invoked on the worker thread with a request to process. * Only one Intent is processed at a time, but the processing happens on a * worker thread that runs independently from other application logic. * So, if this code takes a long time, it will hold up other requests to * the same IntentService, but it will not hold up anything else. * When all requests have been handled, the IntentService stops itself, * so you should not call {@link #stopSelf}. * * @param intent The value passed to {@link * android.content.Context#startService(Intent)}. * This may be null if the service is being restarted after * its process has gone away; see * {@link android.app.Service#onStartCommand} * for details. */ @WorkerThread //抽象方法,必须实现,此方法实现异步任务 protected abstract void onHandleIntent(@Nullable Intent intent);由于IntentService 是继承自Service类,其他使用方式跟Service是一样的,可见另外一篇博客 https://blog.csdn.net/weixin_42042620/article/details/85227601 2.4 ThreadPoolExecutor 1.Executors.newFixedThreadPool() 创建一个定长的线程池,每提交一个任务就创建一个线程,直到达到池的最大长度,这时线程池会保持长度不再变化2.Executors.newCachedThreadPool() 创建一个可缓存的线程池,如果当前线程池的长度超过了处理的需要时,它可以灵活的回收空闲的线程,当需要增加时, 它可以灵活的添加新的线程,而不会对池的长度作任何限制3.Executors.newScheduledThreadPool() 创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer4.Executors.newSingleThreadExecutor() 创建一个单线程化的executor,它只创建唯一的worker线程来执行任务。 2.5 RxJava RxJava 是一个 基于事件流、实现异步操作的库,是一个强大的第三方开源库,随笔的博客https://mp.csdn.net/mdeditor/90745181#。