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

一.引子:

        在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锁。这样就产生了死锁。

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

  •  view.post(Runnable action);
  •  ativity.runOnUiThread(Runnable action);
  •  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.启动策略:

  •  线程池创建时,里面是没有一个线程。任务队列是作为参数传进来的,不过,就算队列里有任务,线程池也不会马上执行它们。
  •  当调用excute()方法添加一个任务是线程池会做出判断:

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

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

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

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

  • 当一个线程完成任务时,它会从队列取下一个任务来执行。
  • 当线程池无事可做时,超过一段时间时线程池会做出判断,如果当前运行的线程数大于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 wangyongyao 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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值