指定Handler中的IsReusable用处?

本文探讨了IHttpHandler接口中IsReusable属性的作用及其对性能的影响。详细解释了当属性设为true时,CLR如何维护对象池来提高性能,并强调了此时必须确保线程安全性和避免依赖于HttpContext.Request的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 以下代码的用处?
public bool IsReusable {
        get {
            return false;
        }
    }

*****************************************
资料1:
*****************************************
IHttpHandler.IsReusable 属性
获取一个值,该值指示其他请求是否可以使用 IHttpHandler 实例。
属性值
如果 IHttpHandler 实例可再次使用,则为 true;否则为 false。
 备注
将 IsReusable 属性用所提供的重写 IsReusable 属性访问器 (getter) 的代码显式设置为 true 或 false。

*****************************************
资料2:
*****************************************
IHttpHandler接口中的属性 IsReusable
Network     2008-09-25
IHttpHandler IsReusable Property
There isn't much clear info regarding this property on the net. It can be better in terms of performance when the property is set to true, but can cause some headaches if you have set it to true in the wrong scenario.

public bool IsReusable
{
   get
   {
      return false;
   }
}
The property is used to indicate if a single intantiation of your IHttpHandler implementation can be used to process multiple concurrent requests. Each client request is considered to be a worker thread on the serverside when being processed through the ASP.NET pipeline. So, if we set IsReusable = true, we need to make sure that our ProcessRequest method is threadsafe. The ProcessRequest should not rely on any state that could be modified by other concurrent request threads. Important when your IHttpHandler implementation does expensive initialisations, otherwise it probabaly doesn't really matter if you return true or false (since simple object allocation is fairly inexpensive in .NET). N.B. Pages are never pooled.

IHttpHandler接口中的属性 IsReusable

在MSDN上对IsReusable的介绍不够清楚。当该属性设置为true,将获得更好的执行性能,但是这在某些情况会引起一些 headcache的问题。
public bool IsReusable
{
 get { return false; }
}
这个属性用来指明,如果你IHttpHandler的实现类的单个实例被用来处理多个请求。当通过ASP.NET 管道处理时,每个客户端请求被服务端认为是一个工作者线程。因此,如果我们设置 IsReusable = true 时,我们需要确信ProcessRequest 方法是线程安全的。 ProcessRequest 应该不会依赖任何有可能被其他请求修改的状态值。当你的IHttpHandler 实现类忙于做初始化时,否则你无需介意IsReusable 返回的是true 或者 false。
————————————————————————
Email:xiumang2006 AT 126.com 备案
开源目录:
http://www.itjewy.com/
*********************************************************
资料3:
*********************************************************
关于HttpHandler的可重用性的思考(关于IsReusable属性的疑惑)

原来一直对这个IHttpHandler的可重用性不太理解,今天看了一篇文章算是有一点感觉了. 总的说来针对每个请求都会由一个HttpHandlerFactory初始化一个对应的IHttpHandler的实例出来,  而这个Handler是否有状态并非取决于这个类是否有成员变量.  而是取决于它是否依赖于HttpContext.Request, 因为它被Factory初始化出来的时候是用这个context作为参数的,应该是这样理解吧.  当IsReusable 为真时, CLR会维护一个对象池, 通常是因为创建这个Handler需要较大的开销时才这么做, 同时它也应该是无状态的.

但是还是有一个问题, 就是IHttpHandler如果让它也支持象Aspx那样的输出缓存呢? 可能还需要继续研究.

那么怎么样的情况才可以重用这个handler 呢,这个就很明显了.  只要它不依赖于context.Request就可以.当然也不能有成员变量.

另外补充一下, 最好不使用.ashx文件,而直接在web.config接定相应的handler的类, 因为这些对更改handler来说更灵活一些,并且. 直接奖代码写在.ashx里面的话它得等到被请求时才会被编译, 稍微影响一点速度. 再有就是考虑到代码安全的问题.

<think>我们被要求详细解释Android中的Handler机制工作原理。根据用户提供的引用内容,我们可以整合出一个全面的解释。Handler机制是Android中用于线程间通信的重要机制,尤其常用于子线程执行任务后更新UI(因为UI操作必须在主线程进行)。核心组件:1.Handler:负责发送和处理消息。2.Message:消息的载体,包含需要传递的数据。3.MessageQueue:消息队列,用于存储Handler发送的消息(实际上是一个按时间排序的优先级队列)。4.Looper:循环取出MessageQueue中的消息,并分发给对应的Handler处理。5.ThreadLocal:用于每个线程存储自己的Looper,实现线程隔离。工作流程:1.首先,在需要创建Handler的线程中,必须先调用Looper.prepare()(主线程在启动时已经初始化了Looper,所以不需要手动调用)。2.Looper.prepare()会创建一个Looper对象,并将其存储到当前线程的ThreadLocal中。同时,Looper内部会创建一个MessageQueue。3.然后调用Looper.loop(),开始循环从MessageQueue中取出消息。4.创建Handler对象,Handler在创建时会绑定当前线程的Looper(通过ThreadLocal获取)以及Looper中的MessageQueue。5.当我们在其他线程中调用Handler的sendMessage()方法时,Handler会将Message放入其绑定的MessageQueue中。6.Looper在循环中不断从MessageQueue中取出消息(如果队列为空则阻塞),然后调用该消息的target(即发送该消息的Handler)的dispatchMessage()方法。7.Handler的dispatchMessage()方法会调用handleMessage()方法,在该方法中处理消息(通常在这里更新UI)。注意点:-一个线程只能有一个Looper,但可以有多个Handler,这些Handler都绑定同一个Looper(也就是同一个线程的Looper)。-主线程(UI线程)在启动时已经调用了Looper.prepareMainLooper()和Looper.loop(),所以我们可以在主线程直接创建Handler。-在子线程中创建Handler,必须先调用Looper.prepare(),然后调用Looper.loop(),否则会报错。源码层面关键点(参考引用[3]和[4]):-Handler发送消息最终会调用到MessageQueue的enqueueMessage方法,将消息插入队列。-Looper.loop()方法中有一个死循环,不断调用MessageQueue的next()方法获取消息,然后通过msg.target.dispatchMessage(msg)分发消息。-消息处理完毕后,系统会回收消息(Message有消息池机制,避免频繁创建对象)。数学描述:假设消息队列为$Q$,消息入队操作$enqueue(Q,m)$,出队操作$dequeue(Q)$。Looper循环可表示为:$$\text{while}(m=dequeue(Q))\neq\text{null}\text{do}\text{process}(m)$$其中$m$为消息,$process(m)$即处理消息。下面我们按步骤详细解释。</think>### Android Handler机制工作原理详解 Handler机制是Android线程间通信的核心框架,主要用于后台线程执行任务后更新UI。其工作原理可分为以下关键组件和流程: --- #### 核心组件与关系 ```mermaid graph TD A[Handler] -->|发送消息| B(MessageQueue) B -->|存储消息| C[Message] D[Looper] -->|循环取出| B D -->|分发消息| A E[ThreadLocal] -->|存储Looper| D ``` 1. **Handler** - 作用:发送消息(`sendMessage()`)和处理消息(`handleMessage()`) - 关键特性:绑定到创建它的线程的Looper - 发送消息流程: ```java handler.sendMessage(msg) → MessageQueue.enqueueMessage() → Looper.loop() → handler.dispatchMessage() ``` 2. **MessageQueue** - 数据结构:基于时间优先级的单链表(`Message`对象链表) - 核心方法: - `enqueueMessage()`:插入消息(按`when`时间排序) - `next()`:阻塞式获取下一条消息(当队列空时进入休眠) 3. **Looper** - 作用:消息循环泵,不断从MessageQueue取出消息分发 - 关键方法: - `prepare()`:初始化当前线程的Looper(存入ThreadLocal) - `loop()`:启动消息循环(死循环调用`queue.next()`) - 主线程Looper初始化: ```java // ActivityThread.main() Looper.prepareMainLooper(); Looper.loop(); ``` 4. **ThreadLocal** - 作用:线程私有数据存储,确保每个线程有独立的Looper - 实现原理:每个线程的`Thread.threadLocals`字段存储专属数据 --- #### 完整工作流程 1. **消息发送** - 子线程调用`handler.sendMessage(msg)` - Handler将消息插入关联的MessageQueue: ```java // Handler.java public boolean sendMessage(Message msg) { return enqueueMessage(queue, msg, uptimeMillis); } ``` 2. **消息存储** - MessageQueue按`msg.when`(触发时间)排序插入链表 - 若队列空或新消息最早,唤醒Looper线程 3. **消息轮询** - Looper.loop() 循环调用`Message msg = queue.next()` - `next()`方法逻辑: - 有消息 → 立即返回 - 无消息 → 调用`nativePollOnce()`进入休眠(Linux epoll机制) 4. **消息分发** - Looper调用`msg.target.dispatchMessage(msg)` - Handler处理消息的优先级: ```mermaid graph LR A[Message.callback] -->|Runnable对象| B B[Handler.mCallback] -->|Callback接口| C C[handleMessage] -->|默认处理| ``` 5. **资源回收** - 消息处理完成后调用`msg.recycleUnchecked()` - Message加入对象池复用(避免频繁GC) --- #### 数学建模 消息队列操作可表示为: $$ \text{dequeue}(Q) = \begin{cases} \text{msg}_i & \text{if } \exists \text{msg}_i \text{ where } t_{\text{msg}_i} \leq t_{\text{now}} \\ \text{wait}(\Delta t) & \text{otherwise} \end{cases} $$ 其中: - $Q$:消息队列 - $t_{\text{msg}_i}$:消息触发时间 - $\Delta t$ = $ \min(t_{\text{msg}_j}) - t_{\text{now}} $ --- #### 关键设计思想 1. **线程隔离** 通过ThreadLocal实现各线程独立的Looper,避免并发冲突[^2]。 2. **阻塞唤醒优化** 使用Linux epoll机制实现空闲时CPU休眠,节省资源[^4]。 3. **对象复用机制** Message池(sPool)减少对象创建开销(类似享元模式)。 4. **线程切换封装** 开发者无需直接操作线程,通过Handler自动切换执行线程。 > 示例:子线程更新UI > ```java > new Thread(() -> { > Message msg = handler.obtainMessage(); > msg.obj = "Data from background"; > handler.sendMessage(msg); // 自动切换到主线程处理 > }).start(); > ``` --- #### 常见问题解析 **为什么主线程不会因Looper.loop()卡死?** - 消息处理是分段执行的,每条消息处理时间必须短(否则ANR) - 空闲时调用`nativePollOnce()`释放CPU资源 **内存泄漏场景**: 匿名Handler持有外部Activity引用 → 解决方案: ```java // 使用静态内部类 + WeakReference static class SafeHandler extends Handler { WeakReference<Activity> ref; SafeHandler(Activity activity) { ref = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { Activity activity = ref.get(); if (activity != null) { /* 更新UI */ } } } ``` Handler机制通过以上设计,实现了高效、安全的跨线程通信,是Android系统流畅运行的基础[^1][^3][^4]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值