Android基础知识

android多线程

2019-03-04  本文已影响179人  Peakmain

进程

进程和线程的区别

多进程的好处

单进程如何实现不同控件之间的数据传输

单进程如何实现不同控件之间的数据传输.png
多进程造成的问题

Serializable接口

序列化和反序列化
序列化:将数据结构或对象转换成二进制的过程
反序列化:将在序列化过程中生成的二进制串转换成数据结构或对象的过程

序列化应用场景

区别.png

Bundle

应用场景

image.png

我们都知道Android中ActivityThread是主线程,那么Android中在什么位置判断是否是主线程呢?

    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

概述

线程:线程是程序执行流的最小单位,进程是线程的容器,一个进程可以有一个或多个线程,各个线程共享进程的内存.

线程的状态

创建线程

多线程的实现一般有以下3种方法

   public  class MainThread extends Thread{
           @Override
           public void run() {
               super.run();
           }
       }
       public  class MainThread implements Runnable{
           @Override
           public void run() {
               
           }
       }
 public  class MainThread implements Callable{

           @Override
           public Object call() throws Exception {
               return null;
           }
       }

一般推荐用实现Runnable接口的方式,其原因是,一个类应该在其需要加强或者修改时才会被继承

线程的优先级

线程创建的时候,子线程继承父线程的优先级。
线程创建后,可通过setPriority方法改变优先级,默认线程优先级是5
线程的优先级是1-10的整数
常见的常量:Thread.MIN_PRIORITY(默认值1),Thread.MAX_PRIORITY(默认值10),Thread.NORM_PRIORITY(默认值5)

不能依靠线程的优先级来决定线程的执行顺序

线程的调度

线程调度器选择优先级最高的线程执行,以下情况会中断线程的执行

多线程简介

多线程是指,一条以上的线程共同完成程序任务的方式。多线程可以提高CPU的利用率,进而提升整体的处理性能

多线程与单线程的对比:
利:程序整体性能提升,程序整体执行效率提高,程序整体体验改善
弊:引入数据同步的问题,过多的线程反而降低程序整体的性能

线程间数据共享与数据传递的方式

多线程的数据同步问题

public class ThreadDemo  {
    static int count;

    public static void main(String[] args) {
        new Task().start();
        new Task().start();
    }
    static class Task extends Thread{
        @Override
        public void run() {
            int temp=count;//获取共享变量的值
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count=temp+1;//修改共享变量的值
            System.out.println("count value  is:"+count);
        }
    }
}

此时打印的结果是一样的,多线程同步与控制的方法,可以使用关键字synchronized关键字修饰代码,其中同步代码类型有:同步代码块,同步方法,同步静态方法,同步类

线程协同类有wait,notify,notifyall

死锁
原因:有时候两个或多个线程需要在共享对象上获取锁 这可能导致死锁

image.png
解决方法:使用一种名为资源排序的简单技术可以轻易的避免死锁。该技术给每一个需要锁的对象指定一个顺序,确保每个线程都按照这个顺序获取锁,就不会再发生死锁

线程池

ThreadPoolExecutor:线程池的核心实现类

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {}

线程处理流程

线程处理流程.png

线程池的种类

   public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

newFixedThreadPool的的corePoolSize和和maximumPoolSize的值都是nThreads,也就意味着FixedThreadPool只有核心线程,没有非核心线程池

  public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

CachedThreadPool没有核心线程,非核心线程是无界的。keepAliveTime设置为60L,则空闲线程等待新任务的最长时间为 60s。在此用了阻塞队列 SynchronousQueue,它是一个不存储元素的阻塞队列

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

SingleThreadExecutor是使用单个工作线程的线程池

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }

ScheduledThreadPool是一个能实现定时和周期性任务的线程池

AsyncTask源码分析

目的:AsyncTask异步刚开会加载方法-->然后执行什么方法-->最终会执行什么方法 异步加载只能调一次;
AsyncTask中有4个核心方法

AsyncTask的用法

AsyncTask asyncTask=new AsyncTask<Void,Void,Void>(){

          @Override
          protected Void doInBackground(Void... params) {
              //请求网络,耗时操作,运行在Thread中
              return null;
          }

          @Override
          protected void onPreExecute() {
              //一调用就会执行的方法,UI线程中
              super.onPreExecute();
          }

          @Override
          protected void onPostExecute(Void aVoid) {
              super.onPostExecute(aVoid);
              //执行完成后返回的方法,运行在UI线程
          }
      };
      asyncTask.execute();
源码分析

首先看 asyncTask.execute();

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
           Params... params) {
    //status默认的状态  private volatile Status mStatus = Status.PENDING;所以第一次不会走向这里
       if (mStatus != Status.PENDING) {
           switch (mStatus) {
         //如果是RUNNING或者FINISHED状态则抛出异常
               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)");
           }
       }
     //设置当前状态为RUNNING,这也是为什么只能执行一次
       mStatus = Status.RUNNING;
     //首先会执行该方法
       onPreExecute();

       mWorker.mParams = params;
      //execute是个接口,看mFuture是怎么被赋值的
       exec.execute(mFuture);

       return this;
   }

AsyncTask<Params, Progress, Result>三个参数解释一下:Params为参数类型,Progress为后台任务执行进度的类型,Result为结果返回类型

  //第一次new的时候就会走向这里
  public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //子线程中调用doInBackground
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                  //最终会调用该方法
                    postResult(result);
                }
                return result;
            }
        };
       //将mWorker设置为callable
        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

我们可以知道FutureTask实际就是一个Runable,所以直接看run方法我们会发现实际最终调用的

result = c.call();//c实际就是callable而callable实际就是调用WorkerRunnable中的call方法
private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
     //Handler发送消息,切换到主线程
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

最终会走到这里

   private void finish(Result result) {
        if (isCancelled()) {
        //如果已经取消,调用oncancelled方法
            onCancelled(result);
        } else {
          //主线程调用该方法
            onPostExecute(result);
        }
       //设置状态为FINISHED
        mStatus = Status.FINISHED;
    }

总结:.execute一调用就会判断当前状态如果状态不对就会抛出异常,然后设置状态为RUNNING,然后执行onPreExecute(), 开一个线程执行 doInBackground(), doInBackground()执行完毕之后会利用Handler发送消息切换主线程中,然后执行onPostExecute()方法,最后把状态置为FINISHED

参考书籍:Android进阶之光》

上一篇 下一篇

猜你喜欢

热点阅读