单线程处理模型

2024-05-06 21:18
文章标签 模型 处理 单线程

本文主要是介绍单线程处理模型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

摘自:http://coolxing.iteye.com/blog/1284476

所谓的started service, 是我对以startService()方法启动的service的叫法. Service运行在所在进程的main thread中. 启动一个service时, 不会自动为该service创建新的thread. 这意味着开发者通常需要为service开启新的线程, 以执行耗时或者阻塞操作—否则可能导致ANR错误的发生. 既然如此, 为何不在activity中直接开启新的线程执行耗时操作或者阻塞操作呢? 原因在于一个包含正在运行的service的进程具有更安全的进程优先级--它的进程优先级至少是service process, 而activity处于后台运行时它的进程优先级为background process, 在系统内存不足时,处于后台运行的activity更有可能被系统杀死. 关于进程优先级, 在我的另一篇博文中有过介绍http://coolxing.iteye.com/blog/1279170.

如果没有调用stopService()方法或者stopSelf()方法, 就算onStartCommand()方法执行完成, 该service仍然处于active状态, 但onStartCommand()方法返回后, 系统可能处于内存不足的缘故摧毁这个service, 如果发生这种情形, 那么系统将尽快重建这个service, 而onStartCommand()方法的返回值用来定义系统该如何重建service, 返回值的可以是以下3个int值中的一个:

  • START_NOT_STICKY, 表明不要重建service. 这可以避免在非必要的情况下浪费系统的资源.
  • START_STICKY, 表明需要重建service, 并在重建service之后调用onStartCommand()方法, 传递给该方法的intent为null.
  • START_REDELIVER_INTENT, 表明需要重建service, 并在重建service之后调用onStartCommand()方法, 传递给该方法的intent为service被摧毁之前接收到的最后一个intent.     

当service第一次被启动时会调用onCreate()方法, 然后再调用onStartCommand()方法. 在该service的生命周期内,如果再次启动这个service, 就会直接调用onStartCommand()方法了.

onStartCommand(Intent intent, int flags, int startid)方法的第一个参数intent就是用于启动该service的intent, 第二个参数flags的值通常为0, 第三个参数startid标识此次启动请求, 通常用于stopSelf(int)方法.

通常情况下, started service应该使用单线程处理多个启动请求, 此时继承IntentService是一个更好的选择, 当然也可以继承Service类, 只是会导致更多的代码. 不过如果started service需要并发处理多个启动请求, 那么只能继承Service类.

继承Service--以单线程的方式处理多个启动请求

         单线程方式处理多个启动请求是大多数时候的选择, 因为该方式可以有效的处理所有请求, 却有着不需要考虑线程安全的优势. 下面的例子使用了HandlerThread和Handler类构建了单线程模型, 关于Handler, Looper, Message等线程相关的概念, 请参考我的另一篇博文http://coolxing.iteye.com/blog/1208371.

Java代码   收藏代码
  1. public class SingleService extends Service {  
  2.    private static final int NEW_INTENT_COMMING = 0;  
  3.    private Handler handler;  
  4.    
  5.    private final class WorkThreadHanlder extends Handler {  
  6.       // 使用指定Looper创建Handler  
  7.       public WorkThreadHanlder(Looper looper) {  
  8.          super(looper);  
  9.       }  
  10.    
  11.       @Override  
  12.       public void handleMessage(Message msg) {  
  13.          if (msg.what == NEW_INTENT_COMMING) {  
  14.             Log.d("SingleService", Thread.currentThread().getName());  
  15.             try {  
  16.                 Thread.sleep(5 * 1000);  
  17.             } catch (InterruptedException e) {  
  18.                 e.printStackTrace();  
  19.             }  
  20.             // arg1中存储的是onStartCommand()方法的startId参数  
  21.             stopSelf(msg.arg1);  
  22.          }  
  23.       }  
  24.    }  
  25.    
  26.    @Override  
  27.    public int onStartCommand(Intent intent, int flags, int startId) {  
  28.       Message msg = handler.obtainMessage();  
  29.       msg.arg1 = startId;  
  30.       msg.what = NEW_INTENT_COMMING;  
  31.       msg.sendToTarget();  
  32.       return START_STICKY;  
  33.    }  
  34.    
  35.    @Override  
  36.    public void onCreate() {  
  37.       super.onCreate();  
  38.       HandlerThread thread = new HandlerThread("work thread",  
  39.             Process.THREAD_PRIORITY_BACKGROUND);  
  40.       // thread启动之后才能调用getLooper()方法获取thread中的Looper对象  
  41.       thread.start();  
  42.       // 使用子线程的Looper创建handler, 该handler绑定在子线程的消息队列上  
  43.       handler = new WorkThreadHanlder(thread.getLooper());  
  44.    }  
  45.    
  46.    @Override  
  47.    public IBinder onBind(Intent intent) {  
  48.       return null;  
  49.    }  
  50. }  

继承IntentService--以单线程的方式处理多个启动请求

         从上面的例子可以看到, 在Service中构建单线程模型需要编写大量代码, 为了简化编程, android提供了IntentService类. IntentService类Service类的子类, 查看源代码可以知道IntentService只是将上例的单线程模型进行了简单的包装, 在handleMessage()方法中调用onHandleIntent()方法进行具体的请求处理, 该方法是一个抽象方法, 需要由开发者提供实现. 以下是IntentService对Service增强之处:

  • 在onCreate()方法中创建了一个子线程, 用于处理所有发送给onStartcommand()方法的intent.
  • 在onStartCommand()方法中将intent和startId存储在Message对象中, 并将该Message发送给子线程的消息队列. 因此同时存在多个启动请求时, 就会将这些请求的intent以Message的形式加入到子线程的消息队列中,然后子线程从队列中不断的取出和处理消息.
  • 由子线程的Handler对象处理消息, Handler对象的handleMessage()方法调用onHandleIntent方法后调用了stopSelf(int)方法, 因此开发者无需考虑service的退出问题.
  • onHandleIntent方法是一个抽象方法, 留待开发者提供具体实现.

因此继承IntentService可以方便的构建单线程处理启动请求的service, 开发者不需要考虑创建线程, 创建Handler, service的退出等复杂的问题, 仅需要提供一个构造函数和实现onHandleIntent方法.

使用IntentService重写上面的例子:

Java代码   收藏代码
  1. public class SingleIntentService extends IntentService {  
  2.    public SingleIntentService() {  
  3.       // 设置子线程名称  
  4.       super("work thread");  
  5.    }  
  6.    
  7.    @Override  
  8.    protected void onHandleIntent(Intent intent) {  
  9.       Log.d("SingleService", Thread.currentThread().getName());  
  10.       try {  
  11.          Thread.sleep(5 * 1000);  
  12.       } catch (InterruptedException e) {  
  13.          e.printStackTrace();  
  14.       }  
  15.    }  
  16. }  

继承Service--并发处理多个请求

         为了并发处理多个请求, 可以在考虑在onStartCommand()方法中启动新的线程处理intent. 这样, 每调用一次startService()方法就会启动一个新的线程处理请求.

Java代码   收藏代码
  1. public class MultipleService extends Service {  
  2.    @Override  
  3.    public IBinder onBind(Intent intent) {  
  4.       return null;  
  5.    }  
  6.     
  7.    @Override  
  8.    public int onStartCommand(Intent intent, int flags, final int startId) {  
  9.       new Thread() {  
  10.          public void run() {  
  11.             Log.d("SingleService", Thread.currentThread().getName());  
  12.             try {  
  13.                 Thread.sleep(5 * 1000);  
  14.             } catch (InterruptedException e) {  
  15.                 e.printStackTrace();  
  16.             }  
  17.             stopSelf(startId);  
  18.          };  
  19.       }.start();  
  20.       return super.onStartCommand(intent, flags, startId);  
  21.    }  
  22. }  
 

这篇关于单线程处理模型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/965401

相关文章

resultMap如何处理复杂映射问题

《resultMap如何处理复杂映射问题》:本文主要介绍resultMap如何处理复杂映射问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录resultMap复杂映射问题Ⅰ 多对一查询:学生——老师Ⅱ 一对多查询:老师——学生总结resultMap复杂映射问题

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Python实现自动化接收与处理手机验证码

《Python实现自动化接收与处理手机验证码》在移动互联网时代,短信验证码已成为身份验证、账号注册等环节的重要安全手段,本文将介绍如何利用Python实现验证码的自动接收,识别与转发,需要的可以参考下... 目录引言一、准备工作1.1 硬件与软件需求1.2 环境配置二、核心功能实现2.1 短信监听与获取2.

Python使用date模块进行日期处理的终极指南

《Python使用date模块进行日期处理的终极指南》在处理与时间相关的数据时,Python的date模块是开发者最趁手的工具之一,本文将用通俗的语言,结合真实案例,带您掌握date模块的六大核心功能... 目录引言一、date模块的核心功能1.1 日期表示1.2 日期计算1.3 日期比较二、六大常用方法详