前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >线程优化

线程优化

作者头像
Yif
发布2020-04-23 17:41:05
1K0
发布2020-04-23 17:41:05
举报
文章被收录于专栏:Android 进阶Android 进阶

线程调度

线程调度原理

  • 任意时刻,只有一个线程占用CPU,处于运行状态
  • 多线程并发,轮流获取CPU使用权
  • JVM 负责线程的调度:按照特定的机制分配CPU使用权

调度模型

  • 分时调度模型:轮流获取,均分CPU时间
  • 抢占式调度模型:优先级高的进行获取,JVM采用

Android 线程调度

注意点

  • 线程避免过多,否则会导致CPU频繁切换,降低线程的运行效率
  • 通过任务重要性决定优先级是那种
  • 优先级还具有继承性,也就是UI线程中创建子线程,那么子线程的优先级与UI线程优先级一样

nice 值

Process中定义,值越小,优先级越高,默认是THREAD_PRIORITY_DEFAULT 0

不同的线程使用

Thread

最简单,常用的线程使用方式 - 不能够重复使用,频繁创建会造成很大的开销 - 在复杂的场景也不容易使用

HandlerThread

自带消息循环的线程 - 串行执行 - 长时间运行,不断从队列中获取任务

HandlerThread 是 Android 封装的一个线程类,将 Thread 跟 Handler 封装。使用步骤如下:

  • 创建 HandlerThread 实例对象 HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");
  • 启动线程 mHandlerThread .start();

创建Handler对象,重写handleMessage方法

代码语言:javascript
复制
<br />    Handler mHandler= new Handler( mHandlerThread.getLooper() ) {
 
           @Override
 
           public boolean handleMessage(Message msg) {
 
               //消息处理
 
               return true;
 
           }
 
     });
 
 
  • 使用工作线程Handler向工作线程的消息队列发送消息:
代码语言:javascript
复制
<br />     Message message = Message.obtain();
 
     message.what = “2”
 
     message.obj = "骚风"
 
     mHandler.sendMessage(message);
 
 
  • 结束线程,即停止线程的消息循环 mHandlerThread.quit();是一个Android线程封装类,将Thread与handler结合使用

优势:

  1. 将loop运行在子线程中处理,减轻了主线程的压力,使主线程更流畅
  2. 串行执行,开启一个线程起到多个线程的作用
  3. 有自己的消息队列,不会干扰UI线程

劣势:

  1. 由于每一个任务队列逐步执行,一旦队列耗时过长,消息延时
  2. 对于IO等操作,线程等待,不能并发

IntentService

IntentService 是 Service 的子类,默认为我们开启了一个工作线程,使用这个工作线程逐一处理所有启动请求,在任务执行完毕后会自动停止服务,使用简单,只要实现一个方法 onHandleIntent,该方法会接收每个启动请求的 Intent,能够执行后台工作和耗时操作。可以启动 IntentService 多次,而每一个耗时操作会以队列的方式在 IntentService 的 onHandlerIntent 回调方法中执行,并且,每一次只会执行一个工作线程,执行完第一个再执行第二个。并且等待所有消息都执行完后才终止服务。

IntentService 适用于 APP 在不影响当前用户的操作的前提下,在后台默默的做一些操作。

IntentService源码:

  • 通过 HandlerThread 单独开启一个名为 IntentService 的线程
  • 创建一个名叫 ServiceHandler 的内部 Handler
  • 把内部Handler与HandlerThread所对应的子线程进行绑定
  • 通过 onStartCommand() 传递给服务 intent,依次插入到工作队列中,并逐个发送给 onHandleIntent()
  • 通过 onHandleIntent() 来依次处理所有 Intent 请求对象所对应的任务
  • 如果start了多次,每一次都会在WorkerThread中依次执行,当全部执行完成,它就会自己调用stopSelf()结束自己。

使用示例:

代码语言:javascript
复制
<br />public class MyIntentService extends IntentService {
 
    public static final String TAG ="MyIntentService";
 
    public MyIntentService() {
 
        super("MyIntentService");
 
    }
 
 
 
    @Override
 
    protected void onHandleIntent(@Nullable Intent intent) {
 
 
 
       boolean isMainThread = Thread.currentThread() == Looper.getMainLooper().getThread();
 
        Log.i(TAG,"is main thread:"+isMainThread); // 这里会打印false,说明不是主线程
 
 
 
        // 模拟耗时操作
 
        download();
 
    }
 
 
 
    /**
 
     * 模拟执行下载
 
     */
 
    private void download(){
 
       try {
 
           Thread.sleep(5000);
 
           Log.i(TAG,"下载完成...");
 
       }catch (Exception e){
 
           e.printStackTrace();
 
       }
 
    }
 
}
 
 

AsyncTask

Android 提供工具类,无需自己处理线程切换 使用及源码详解见 https://www.ztzyif.top/index.php/2019/07/16/asynctask-%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90/

线程池

Java提供的线程池 - 容易复用,减少频繁创建及销毁时间 - 功能强大:定时、任务队列,并发控制

RxJava

由强大的Scheduler集合组成 源码详解见 https://www.ztzyif.top/index.php/2019/07/17/rxjava2-%e8%a7%a3%e6%9e%90/

线程使用准则

创建线程必须命名 - 方便进行定位线程归属 - 运行期间调用Thread.currentThread.setName()修改名字

重视优先级设置 Process.setThreadPriority()

代码语言:javascript
复制
public class ThreadPoolUtils {
 
    private int CPUCOUNT = Runtime.getRuntime().availableProcessors();
 
    private ThreadPoolExecutor cpuExecutor = new ThreadPoolExecutor(CPUCOUNT, CPUCOUNT,
            30, TimeUnit.SECONDS, new LinkedBlockingDeque&lt;Runnable&gt;(), sThreadFactory);
 
    private ThreadPoolExecutor iOExecutor = new ThreadPoolExecutor(64, 64,
            30, TimeUnit.SECONDS, new LinkedBlockingDeque&lt;Runnable&gt;(), sThreadFactory);
 
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
 
//对每个线程进行命名,原子性的自增       
        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "ThreadPoolUtils #" + mCount.getAndIncrement());
        }
    };
 
    public static ExecutorService getService() {
        return sService;
    }
 
    private static ExecutorService sService = Executors.newFixedThreadPool(5, new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r, "ThreadPoolUtils");
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            return thread;
        }
    });
}
 
代码语言:javascript
复制
// 以下代码是为了演示修改任务的名称
        ThreadPoolUtils.getService().execute(new Runnable() {
            @Override
            public void run() {
                Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
                String oldName = Thread.currentThread().getName();
                Thread.currentThread().setName("new Name");
                LogUtils.i("");
                Thread.currentThread().setName(oldName);
            }
        });
 

统一线程库

  1. 区分任务类型:IO、CPU密集型
  2. IO密集型任务不消耗CPU,核心池可以很大
  3. CPU密集型:核心池与CPU核数有关
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020年4月22日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 线程调度
    • 线程调度原理
      • 调度模型
      • Android 线程调度
        • 注意点
          • nice 值
          • 不同的线程使用
            • Thread
              • HandlerThread
              • IntentService
              • AsyncTask
              • 线程池
              • RxJava
              • 线程使用准则
              • 统一线程库
              相关产品与服务
              消息队列 CMQ 版
              消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档