线程基础、同步、阻塞队列、线程池、AsynTask异步任务

 

一:线程基础

1.进程与线程

进程:是操作系统结构的基础,是程序在一个数据集合上的运行过程,是系统进行资源分配和调度的基本单位。

线程:是操作系统调度的最小单位。

2.线程的状态

New:新创建状态。

Runnable:可运行状态。(注意:此状态不一定在运行,主要取决于cpu是否给线程运行起来)

Blocked:阻塞状态。表示被锁阻塞,他暂时不活动。

Waiting:等待状态。线程暂时不活动。

Timed waiting:超时等待状态。和等待状态不同,在规定时间内会被自动唤醒。

Terminated:终止状态。表示线程已经执行完毕。

具体关于状态详细内容可以参考:

3.创建线程

①.继承Thread类,实现run()方法

②.实现Runnable方法,并实现接口的run()方法

③.实现Callable接口,重写call()方法。是线程池中的方法,Callable属于Executor框架功能类

    一般推荐使用第二种,实现Runnable方法。

4.理解中断

①.Thread.currentThread.isInterrupted()方法使其线程中断

②.在线程处于阻塞情况下中断标识符为true会抛出异常InterruptedException,应该对异常进行处理

③.调用中断方法并不一定会中断,如果线程比较重要,则不会被中断。

 

二:同步

同步:解决线程高并发问题。

1.重入锁与条件对象

重入锁ReentrantLock(相当于synchronized)是Java 5.0引入的,重入锁结构确保任何时刻只有一个线程进入临界区。如下所示结构

临界区就是同一时刻只能有一个任务访问的代码区。

注意在finally释放锁。如下所示。

Lock mLock = new ReentrantLock();
mLock.lock();
try{
...
}
finally{
mLock.unlock();
}

一个锁对象可以获得多个条件对象,可以用newCondition方法获得一个条件对象。

得到条件对象后调用await方法(相当于wait方法),当前线程就放弃锁,进入等待队列。

同一条件对象调用signalAll(相当于notifyAll)方法会重新激活这一条件等待的所有线程。

同一条件对象调用signal(相当于notify)方法会随机激活一个同一对象的线程。

同步代码块一般比较脆弱,尽量使用同步方法。

2.volatile

volatile关键字为实例域的同步访问提供了免锁机制。

①.Java内存模型抽象概念:线程的共享变量存在主存中,每个线程有一个私有的本地内存,本地内存存储着共享变量的副本。如下图:

Android 开启线程结束线程 android 线程状态_线程池

②.并发编程的三个特性:原子性、可见性和有序性

原子性:操作不可中断

可见性:一个线程修改状态对另一个线程可见

有序性:Java内存模型中允许编译器和处理器对指令进行重排序,禁止重排序就是具有有序性

volatile保证可见性、有序性;不保证原子性

正确使用关键字volatile:

①.对变量的写操作不能依赖当前值。

②.该变量没有包含在其他变量的不变式中。

本质:volatile变量操作中不能有volatile变量,因为保证不了原子性。

volatile使用场景:

①.状态标志

②.双重检查模式

 

三:阻塞队列

1.阻塞队列:常用于生产者和消费者的场景,生产者往队列里面放元素,消费者从队列里面拿元素。

2.Java中提供七种阻塞队列:

ArrayBlockingQueue:由数组结构组成的有界阻塞队列。(重点)

LinkedBlockingQueue:有链表结构组成的有界阻塞队列。(重点)

PriorityBlockingQueue:支持优先级的无解阻塞队列。

DelayQueue:支持延时获取元素的无界阻塞队列。(重点)

SynchronousQueue:不存储元素的阻塞队列。(重点)

LinkedTransferQueue:由链表结构组成的无界阻塞队列。

LinkedBlockingDeque:由链表结构组成的双向阻塞队列。

3.阻塞队列的实现:内存通过重入锁与条件对象的等待和解除等待机制。

4.使用场景:生产者消费者场景。

 

四.线程池

1.ThreadPoolExecutor线程池拥有最多参数的构造方法如下代码:

public ThreadPoolExecutor(int corePoolSize,                        //核心线程数
                              int maximumPoolSize,                 //最大线程数
                              long keepAliveTime,                  //闲置时间     
                              TimeUnit unit,                       //时间单位
                              BlockingQueue<Runnable> workQueue,   //阻塞队列
                              ThreadFactory threadFactory,         //线程工厂:主要给线程起名
                              RejectedExecutionHandler handler) {...}    //饱和策略

2.线程池的处理流程及原理:

Android 开启线程结束线程 android 线程状态_线程池_02

                      

Android 开启线程结束线程 android 线程状态_线程池_03

如上图,执行ThreadPoolExecutor的executor方法,会遇到各种情况:

①.如果线程池未达到核心线程数,创建核心线程处理任务。

②.线程池超过核心线程数,将任务放入任务队列中,线程池中有空闲线程会不断地从任务队列中取出任务进行处理。

③.如果任务队列满了,并且线程数没有达到最大线程数,则创建非核心线程去处理任务。

④.如果线程数超过了最大线程数,执行饱和策略。

2.线程的种类:

①.FixedThreadPool:固定可重用线程数的线程池。构造方法如下:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads,         //核心线程数nThreads个
                                      nThreads,         //最大线程数nThreads个,非核心线程0个
                                      0L, TimeUnit.MILLISECONDS,              //闲置时间0
                                      new LinkedBlockingQueue<Runnable>());   //链表阻塞队列
    }

②.CacheThreadPool:根据需要创建的线程池,适合于大量且耗时短的任务,构造方法如下:

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,      //核心线程0个,非核心线程无界
                                      60L, TimeUnit.SECONDS,     //空线程等待任务时间60s(最多闲置60s)被销毁
                                      new SynchronousQueue<Runnable>());    //不存储元素的阻塞队列
    }

③.SingleThreadExecutor:单个工作线程的线程池

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

④.ScheduledThreadPool:实现定时和周期任务的线程池,最终调用构造方法如下

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());        //延时队列
    }

 

五.AsyncTask原理:

1.AsyncTask五个核心方法:

onPreExecute():在主线程执行,一般是在任务执行之前做准备工作。

doInBackground(Params...params):在线程池中执行,用来执行耗时操作。调用publishProgress(Progress...values)来更新信息。

onProgressUpdate(Progress... values):在主线程执行,当调用publishProgress(Progress...values)时此方法用来更新ui组件。

onPostExecute(Result result):在主线程中执行。当后台任务执行完成就调用此方法,doInBackground的返回值就是参数result。

onCancelled(Result result):主线程中执行。如果任务被取消此方法就会被调用,doInBackground的返回值就是参数result。

2.android 3.0之前是并行执行任务,当提交139个任务会执行饱和策略。android 3.0之后是串行执行任务,不会发生饱和。

3.异步任务原理是:线程池+Handler机制

4.也可以调用asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"")执行并行策略。

5.可以改变线程池还可以传入自定义线程池:本质都是调用executeOnExecutor()方法。