Android中线程的相关知识及线程池的管理工具类

来源:互联网 发布:竹笛教学的软件 编辑:程序博客网 时间:2024/06/13 23:14

一.引子:在Android默认主线程(UI线程)不能进行耗时操作的,如果在主线程中进行了耗时的操作会导致ANR,所以在很多的操作必然会开启新的线程去做耗时的操作。

二.线程的开启有两种方式及线程相关知识:

  1.继承Thread类创建线程类:首先,定义Thread类的子类,并重写该类的run()方法,这个方法就代表了线程要完成的任务,因此把run()方法称为执行体;再者,创建Thread子类的实例,即创建线程对象;最后,调用线程对象start()方法启动该线程。

  2.实现Runnable接口创建线程类:首先定义Runnable接口的实现类,并重写该接口run()方法的方法体;再者,创建Runnable实现类的实例,并以此作为Thread来创建对象,这个就是真正的线程对象;最后调用线程对象的start()方法启动该线程。

  3.线程的共享资源:

     在Thinking in java中有这样一段文字“对一种特殊的资源—— 对象中的内存—— Java 提供了内建的机制来防止它们的冲突。由于我们通常将数据元素设为从属于 private(私有)类,然后只通过方法访问那些内存,所以只需将一个特定的方法设synchronized(同步的),便可有效地防止冲突。在任何时刻,只可有一个线程调用特定对象的一个synchronized 方法(尽管那个线程可以调用多个对象的同步方法)。每个对象都包含了一把锁(也叫作“监视器”),它自动成为对象的一部分(不必为此写任何特殊的代码)。调用任何 synchronized 方法时,对象就会被锁定,不可再调用那个对象的其他任何synchronized 方法,除非第一个方法完成了自己的工作,并解除锁定。”这句话大有裨益啊!想保护其他某些资源不被多个线程同时访问时,可以强制通过synchronized防止访问那些资源。

   4.阻塞及死锁:

     Thinking in java描述了五种可能造成阻塞的原因:1).调用sleep()使线程进入睡眠状态;2).supend()暂停线程执行;3).wait()暂停线程执行;4).线程正在等候IO操作;5).线程试图调用另一个对象的同步方法,但那个对象处于锁定状态,暂时无法使用。

     死锁问题:如果A线程执行同步代码块,在同步代码块中又有同步。所以A线程拥有object锁的同时又获得了this锁,此时B线程进行同步函数,由于A已经获取了this的锁,两个都在等待对象释放this锁。这样就产生了死锁。

三.子线程回调主线程的方式:

  1.view.post(Runnable action);

  2.ativity.runOnUiThread(Runnable action);

  3.Handler的消息机制:

作用:

是由于主线程中操作会导致ANR异常,所以需要将网络请求耗时操作放在子线程中进行,但是子线程中不能操作UI,所以需要将子线程中获取到的数据传递到UI线程中进行UI更新。这样Handler机制及应运而生。

使用:首先在主线程中创建Handler对象,重写handlerMessage方法。用该handler对象在子线发送消息,然后在主线程的handlerMessage方法中处理消息。接下来handler.post(Runnable runnable)。

组成:handler消息机制有四大组成部分,分别是:

 1).Handler:用于发送消息和处理消息。

 2).Message:用于携带数据和通知。

 3).MessageQueue:用于储存消息,它内部是单链表实现的

 4).Looper:无限循环的轮训器,用于从MessageQueue中取出消息,并交给Handler处理。

在主线程中默认是初始化了Looper,在子线程中并没有这样做。如果要实现主线程向子线程中传递数据,那么必须在子线程中new一个Handler对象,然后用该handler对象然后用该handler对象在主线程发送消息到子线程。注意的是必须也要在子线程中进行Looper的初始化Looper.prepare和Looper.loop,这样才能实现主线程向子线程发送消息。

四.线程优化:

1.在程序中大量的创建线程势必会产生大量线程开启和关闭的操作,这样会带来性能开销。所以才有了线程这种方法对此进行优化。

线程池内部重用线程,可避免创建和销毁带来的性能开销,同时还能控制线程池最大并发数,避免大量线程因互相抢占系统资源导致阻塞现象。

线程池的就是事先将多个线程对象放在一个容器中,当使用时不用new线程而是直接去线程池中拿即可,省了开辟子线程的时间。

2.好处:降低资源消耗,通过重复利用,提高响应速度,提高线程的可管理性。

3.启动策略:

  1).线程池创建时,里面是没有一个线程。任务队列是作为参数传进来的,不过,就算队列里有任务,线程池也不会马上执行它们。

  2).当调用excute()方法添加一个任务是线程池会做出判断:

     (1).如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行任务。

     (2).如果这时候的线程数量大于或等于corePoolSize,那么放入队列队列中。

     (3).队列满时,而且正在运行线程数小于maximumPoolSize,那么还是创建运行。

     (4).队列满时,而且正在运行线程大于或等于maximumPoolSize,那么会抛出异常告诉调用者,不在接受任务。

   3).当一个线程完成任务时,它会从队列取下一个任务来执行。

   4).当线程池无事可做时,超过一段时间时线程池会做出判断,如果当前运行的线程数大于corePoolSize,那么这些线程会别停掉,所以线程池的所有任务完成后,它最终收缩到corePoolSize的大小。

4.在Android中有这么一个ThreadPoolExecutor类,其大概由四个基本组成部分:

    1).线程管理器ThreadPool:主要功能是创建、管理、添加线程;

    2).工作线程PoolWorker:在没有线程池处于等待循环执行;

    3).任务接口Task:主要规定任务入口、执行状态;

    4).任务队列TaskQueue:用于存放没有处理的任务,提供缓存。

5.ThreadPoolExecutor类构造方法中有五个重要的参数:

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

   1).corePoolSize:核心线程数,一直存活并处于闲置;

   2).maximumPoolSize:最大线程数,达到最大任务数新任务将会被阻塞;

   3).keepAliveTime:非核心线程闲置时超时时长;

   4).workQueue:任务通过线程池的excute方法提交的Runnable对象会存储在这个参数中;

   5).threadFactory:线程工厂

6.java中Excutor类中默认创建四种类型的线程池:

   1).newFixThreadPool:它是一种线程固定的线程池,当线程处于空闲状态时,它不用被回收除非线程池被关闭。

   2).newCachedThreadPool:线程数量不定的线程池,它只有非核心线程。

   3).newScheduledThreadPool:核心线程数量固定,非核心线程没有限制,非核心线程闲置时会被回收。

   4).newSingleThreadExecutor:只有核心线程,它确保所有任务都在同一个线程中按顺序执行。

7.自己实现了一个ThreadManager的线程管理类:

package com.example.foreveross.clickdemo;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.RejectedExecutionHandler;import java.util.concurrent.ThreadFactory;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;/** * Created by Foreveross on 2017/4/15. */public class ThreadManager {    // 定义两个池子,mNormalPool 访问网络用的,mDownloadPool 是下载用的    private static ThreadPoolProxy mNormalPool   = new ThreadPoolProxy(1, 3, 5 * 1000);//param 0  最大线程数,param 1 核心线程数    private static ThreadPoolProxy mDownloadPool = new ThreadPoolProxy(3, 3, 5 * 1000);    // proxy 是代理的意思    // 定义两个get方法,获得两个池子的对象 ,直接get 获得到的是代理对象    public static ThreadPoolProxy getNormalPool() {        return mNormalPool;    }    public static ThreadPoolProxy getDownloadPool() {        return mDownloadPool;    }    // 代理设计模式类似一个中介,所以在中介这里有我们真正想获取的对象    // 所以要先获取代理,再获取这个线程池    public static class ThreadPoolProxy {        private final int                mCorePoolSize;     // 核心线程数        private final int                mMaximumPoolSize;  // 最大线程数        private final long               mKeepAliveTime;    // 所有任务执行完毕后普通线程回收的时间间隔        private ThreadPoolExecutor mPool;  // 代理对象内部保存的是原来类的对象        // 赋值        public ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long keepAliveTime) {            this.mCorePoolSize = corePoolSize;            this.mMaximumPoolSize = maximumPoolSize;            this.mKeepAliveTime = keepAliveTime;        }        private void initPool() {            if (mPool == null || mPool.isShutdown()) {                //                int corePoolSize = 1;//核心线程池大小                //                int maximumPoolSize = 3;//最大线程池大小                //                long keepAliveTime = 5 * 1000;//保持存活的时间                TimeUnit unit      = TimeUnit.MILLISECONDS;//单位                BlockingQueue<Runnable> workQueue = null;//阻塞队列                workQueue = new ArrayBlockingQueue<Runnable>(3);//FIFO,大小有限制,为3个                //workQueue = new LinkedBlockingQueue();  //队列类型为linked,其大小不定,无限大小                //                workQueue = new PriorityBlockingQueue();                ThreadFactory threadFactory = Executors.defaultThreadFactory();//线程工厂                RejectedExecutionHandler handler = null;//异常捕获器                //                handler = new ThreadPoolExecutor.DiscardOldestPolicy();//去掉队列中首个任务,将新加入的放到队列中去                //                handler = new ThreadPoolExecutor.AbortPolicy();//触发异常                handler = new ThreadPoolExecutor.DiscardPolicy();//不做任何处理                //                handler = new ThreadPoolExecutor.CallerRunsPolicy();//直接执行,不归线程池控制,在调用线程中执行                //                new Thread(task).start();                // 创建线程池                mPool = new ThreadPoolExecutor(mCorePoolSize,                        mMaximumPoolSize,                        mKeepAliveTime,                        unit,                        workQueue,                        threadFactory,                        handler);            }        }        /**         * 执行任务         * @param task         */        public void execute(Runnable task) {            initPool();            //执行任务            mPool.execute(task);        }        // 提交任务        public Future<?> submit(Runnable task) {            initPool();            return mPool.submit(task);        }        // 取消任务        public void remove(Runnable task) {            if (mPool != null && !mPool.isShutdown()) {                mPool.getQueue()                        .remove(task);            }        }    }}


0 0
原创粉丝点击