Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式

合集下载

JavaExecutorService四种线程池及自定义ThreadPoolExecutor机制

JavaExecutorService四种线程池及自定义ThreadPoolExecutor机制

JavaExecutorService四种线程池及⾃定义ThreadPoolExecutor机制⼀、Java 线程池Java通过Executors提供四种线程池,分别为:1、newCachedThreadPool:创建⼀个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。

(线程最⼤并发数不可控制);线程池为⽆限⼤,当执⾏第⼆个任务时若第⼀个任务已经完成,会复⽤执⾏第⼀个任务的线程,⽽不⽤每次新建线程。

2、newFixedThreadPool:创建⼀个定长线程池,可控制线程最⼤并发数,超出的线程会在队列中等待。

3、newScheduledThreadPool:创建⼀个定长线程池,⽀持定时及周期性任务执⾏、延迟执⾏。

4、newSingleThreadExecutor:创建⼀个单线程化的线程池,它只会⽤唯⼀的⼯作线程来执⾏任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执⾏。

线程池⽐较单线程的优势在于:a. 重⽤存在的线程,减少对象创建、消亡的开销,性能佳。

b. 可有效控制最⼤并发线程数,提⾼系统资源的使⽤率,同时避免过多资源竞争,避免堵塞。

c. 提供定时执⾏、定期执⾏、单线程、并发数控制等功能。

⼆、ThreadPoolExecutor机制1、newCachedThreadPool在newCachedThreadPool中如果线程池长度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。

初看该构造函数时我有这样的疑惑:核⼼线程池为0,那按照前⾯所讲的线程池策略新任务来临时⽆法进⼊核⼼线程池,只能进⼊ SynchronousQueue中进⾏等待,⽽SynchronousQueue的⼤⼩为1,那岂不是第⼀个任务到达时只能等待在队列中,直到第⼆个任务到达发现⽆法进⼊队列才能创建第⼀个线程?这个问题的答案在上⾯讲SynchronousQueue时其实已经给出了,要将⼀个元素放⼊SynchronousQueue中,必须有另⼀个线程正在等待接收这个元素。

Java线程池ExecutorService详解及实例代码

Java线程池ExecutorService详解及实例代码

Java线程池ExecutorService详解及实例代码Java 线程池ExecutorService1.线程池 1.1什么情况下使⽤线程池1. 单个任务处理的时间⽐较短.2. 将需处理的任务的数量⼤.1.2使⽤线程池的好处1. 减少在创建和销毁线程上所花的时间以及系统资源的开销.2. 如果不使⽤线程池,有可能造成系统创建⼤量线程⽽导致消耗系统内存以及”过度切换”;2.ExecutorService和Executors2.1简介ExecutorService是⼀个接⼝,继承了Executor,public interface ExecutorService extend Executor{}Executor也是⼀个接⼝,该接⼝只包含⼀个⽅法:public interface Executor {void execute(Runnable command);}Java⾥⾯的线程池的顶级接⼝是Excutor,但是严格意义上来说>>Exector并不是⼀个线程池,⽽只是⼀个执⾏线程的⼯具,真正的线程>池接⼝是ExecutorService.3.Executors它是⼀个静态⼯⼚类,它能⽣产不同类型的线程池,部分源码如下:public class Executors {//newFixedThreadPoolpublic static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads, 0L, LISECONDS,new LinkedBlockingQueue<Runnable>());}//newCacheThreadPoolpublic static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}//newScheduledThreadPoolpublic static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);}//newStringooo}先看⼀个具体的例⼦,⽤例⼦来说明它们之间的异同.package thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;/*** Created by yang on 16-7-11.*/public class Ch09_Executor {private static void run(ExecutorService threadPool) {for (int i = 1; i < 5; i++) {final int taskID=i;try{Thread.sleep(20);}catch (InterruptedException e){e.printStackTrace();}System.out.println("第"+taskID+"次任务的第"+i+"次执⾏");}}});}threadPool.shutdown();}public static void main(String[] args) {//创建可以容纳3个线程的线程池ExecutorService fixedThreadPool= Executors.newFixedThreadPool(3);//线程池的⼤⼩会根据执⾏的任务动态的分配ExecutorService cacheThreadPool=Executors.newCachedThreadPool();//创建单个线程的线程池,如果当前线程在执⾏任务时突然中断,则会创建⼀个新的线程替换它继续执⾏.ExecutorService singleThreadPool=Executors.newSingleThreadExecutor();//效果类似于Timer定时器ScheduledExecutorService scheduledThreadPool=Executors.newScheduledThreadPool(3);// run(fixedThreadPool); //(1)//run(cacheThreadPool); //(2)// run(singleThreadPool); //(3)// run(scheduledThreadPool); //(4)}}4. 4种常⽤的线程池4.1 CachedThreadPoolCachedThreadPool会创建⼀个缓存区,将初始化的线程缓存起来,会终⽌并且从缓存中移除已有6秒未被使⽤的线程. 如果线程有可⽤,就使⽤之前创建好的线程.如果线程没有可⽤的,就新创建线程..重⽤:缓存型池⼦,先看看池中有没有以前建⽴的线程,如果有,就reuse,如果没有,就新建⼀个新的线程加⼊池中,使⽤场景:缓存型池⼦通常⽤于执⾏⼀些⽣存期很短的异步型任务,因此在⼀些⾯向连接的Daemon型SERVER中⽤地不多.超时:能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终⽌及移除池.结束:放⼊CachedThreadPool的线程不必担⼼其结束,超过TIMEOUT不活动,其会被⾃动终⽌.实例解说:去掉(2)的注释,运⾏,得到的运⾏结果如下:第1次任务的第1次执⾏第3次任务的第1次执⾏第2次任务的第1次执⾏第4次任务的第1次执⾏第3次任务的第2次执⾏第1次任务的第2次执⾏第2次任务的第2次执⾏第4次任务的第2次执⾏第3次任务的第3次执⾏第1次任务的第3次执⾏第2次任务的第3次执⾏第4次任务的第3次执⾏从结果可以看出,4个任务是交替执⾏的.4.2FixedThreadPool在FixedThreadPool中,有⼀个固定⼤⼩的池,如果当前需要执⾏的任务超过池⼤⼩,那么多出去的任务处于等待状态,直到有空闲下来的线程执⾏任务。

executorservice 线程池造成内存溢出解决方法

executorservice 线程池造成内存溢出解决方法

executorservice 线程池造成内存溢出解决方法内存溢出(OutOfMemoryError)通常是由于程序尝试使用的内存超过了Java虚拟机(JVM)的限制所致。

在使用`ExecutorService`和线程池时,可能存在一些常见的问题导致内存溢出。

以下是一些建议的解决方法:1. 合理配置线程池大小:-确保你的线程池大小合理。

如果创建了过多的线程,可能会导致内存溢出。

合理配置线程池的大小可以根据系统的硬件配置、可用内存和任务的性质。

2. 使用有界队列:-如果任务提交速度大于线程池处理速度,可能会导致内存溢出。

使用有界队列可以防止任务无限制地排队,从而保护系统不至于过载。

3. 考虑使用`ThreadPoolExecutor`的其他构造函数:- `ThreadPoolExecutor`有多个构造函数,允许你更详细地配置线程池。

你可以通过调整参数,例如`corePoolSize`、`maximumPoolSize`、`keepAliveTime`等来适应不同的需求。

4. 使用`ExecutorService`的`shutdown`方法:-确保在不需要线程池时调用`shutdown`方法来关闭线程池。

这可以确保线程池中的所有线程都被正确地关闭,释放相关资源。

```javaExecutorService executorService = Executors.newFixedThreadPool(10);// 在不再需要线程池时调用shutdownexecutorService.shutdown();```5. 处理任务异常:-如果你的任务中有可能抛出异常,确保在任务内部捕获并处理异常。

未处理的异常可能导致线程池中的线程意外终止,从而引发内存溢出。

6. 检查任务队列和线程池是否被正确关闭:-在应用程序生命周期结束时,确保线程池和相关资源被正确关闭。

这可以通过在适当的时候调用`shutdown`和`awaitTermination`来实现。

executorservice 7个参数

executorservice 7个参数

ExecutorService,是Java中用于处理任务的工具。

它提供了强大的任务调度功能,可以替代Timer类来处理需要延迟执行、定期执行或者需要在某个时间间隔内重复执行的任务。

下面将详细介绍ExecutorService的7个参数。

1. corePoolSize:这是线程池中的核心线程数,它表示了线程池中的最小线程数,也就是在任何时候,至少会有corePoolSize个线程在等待任务执行。

2. maxiumPoolSize:这是线程池中的最大线程数,它表示了线程池中的最大线程数,也就是在任何时候,最多会有maxiumPoolSize 个线程在等待任务执行。

当线程数量超过这个最大值时,就会触发拒绝策略,将部分任务拒绝处理。

3. keepAliveTime:这是线程在空闲状态下持续保持的时间,当线程没有执行任务时,如果超过了这个时间,那么该线程就会被销毁。

4. TimeUnit:这是保持线程空闲状态时所采用的时间单位。

常见的时间单位有:SECONDS,MINUTES,HOURS,DAYS。

5. workQueue:这是任务的存储队列,如果任务数超过了核心线程数和队列长度的总和,就会触发拒绝策略。

当队列满时,会执行拒绝策略。

6. threadFactory:这是用于构建线程的函数,用于创建线程时传入一些额外的信息,比如线程名称。

通常使用ThreadFactory来构建线程池。

7. handler:这是处理任务执行结果的处理器,用于处理任务执行结束后的结果,通常用于收集统计数据、进行错误处理等。

需要注意的是,以上的参数只是一些常见的配置,实际的参数还可能因需要进行个性化的配置。

同时,ExecutorService无法保证定时任务的绝对执行精度,高并发下的性能可能受限。

在使用过程中,还需要注意合理配置线程池大小,并在使用完毕后及时关闭线程池,以避免不必要的资源浪费。

关于线程池的五种实现方式,七大参数,四种拒绝策略

关于线程池的五种实现方式,七大参数,四种拒绝策略

关于线程池的五种实现⽅式,七⼤参数,四种拒绝策略⼀、池化技术之线程池什么是池化技术?简单来说就是优化资源的使⽤,我准备好了⼀些资源,有⼈要⽤就到我这⾥拿,⽤完了就还给我。

⽽⼀个⽐较重要的的实现就是线程池。

那么线程池⽤到了池化技术有什么好处呢?降低资源的消耗提⾼响应的速度⽅便管理也就是 线程复⽤、可以控制最⼤并发数、管理线程⼆、线程池的五种实现⽅式其实线程池我更愿意说成四种封装实现⽅式,⼀种原始实现⽅式。

这四种封装的实现⽅式都是依赖于最原始的的实现⽅式。

所以这⾥我们先介绍四种封装的实现⽅式newSingleThreadExecutor()这个线程池很有意思,说是线程池,但是池⼦⾥⾯只有⼀条线程。

如果线程因为异常⽽停⽌,会⾃动新建⼀个线程补充。

我们可以测试⼀下:我们对线程池执⾏⼗条打印任务,可以发现它们⽤的都是同⼀条线程public static void test01() {ExecutorService threadPool = Executors.newSingleThreadExecutor();try {//对线程进⾏执⾏⼗条打印任务for(int i = 1; i <= 10; i++){threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"=>执⾏完毕!");});}} catch (Exception e) {e.printStackTrace();} finally {//⽤完线程池⼀定要记得关闭threadPool.shutdown();}}pool-1-thread-1=>执⾏完毕!pool-1-thread-1=>执⾏完毕!pool-1-thread-1=>执⾏完毕!pool-1-thread-1=>执⾏完毕!pool-1-thread-1=>执⾏完毕!pool-1-thread-1=>执⾏完毕!pool-1-thread-1=>执⾏完毕!pool-1-thread-1=>执⾏完毕!pool-1-thread-1=>执⾏完毕!newFixedThreadPool(指定线程数量)这个线程池是可以指定我们的线程池⼤⼩的,可以针对我们具体的业务和情况来分配⼤⼩。

executorservice线程池正确使用方法

executorservice线程池正确使用方法

executorservice线程池正确使用方法(实用版3篇)目录(篇1)1.引言2.ExecutorService 线程池简介3.线程池的创建与使用3.1 创建线程池3.2 线程池的执行任务3.3 线程池的关闭4.线程池的参数配置4.1 核心线程数4.2 最大线程数4.3 队列容量4.4 时间单位5.线程池的优点与适用场景6.线程池的注意事项7.结论正文(篇1)1.引言在 Java 多线程编程中,ExecutorService 线程池是一种非常常用的工具,它能够有效地管理和控制线程的创建与执行。

本文将介绍ExecutorService 线程池的正确使用方法。

2.ExecutorService 线程池简介ExecutorService 是 Java 并发包中的一个接口,它提供了一种将任务提交到线程池的方法。

线程池可以自动地根据任务数量创建和销毁线程,从而避免了手动管理线程的复杂性和资源消耗。

3.线程池的创建与使用3.1 创建线程池要创建一个线程池,可以使用 Executors 类中的静态工厂方法。

例如,创建一个固定大小的线程池可以使用以下代码:```javaExecutorService executorService =Executors.newFixedThreadPool(5);```3.2 线程池的执行任务创建线程池后,可以将任务提交到线程池中执行。

常用的提交任务方法有:- execute(Runnable command):提交一个实现 Runnable 接口的任务- execute(Callable<T> command):提交一个实现 Callable 接口的任务,并返回任务的结果- execute(Runnable command, T value):提交一个实现 Runnable 接口的任务,并传递一个参数值示例:```javaexecutorService.execute(new Runnable() {@Overridepublic void run() {// 任务代码}});```3.3 线程池的关闭在完成任务后,应关闭线程池以释放资源。

java 线程池 参数

java 线程池参数摘要:1.Java 线程池简介2.Java 线程池的参数3.参数详解3.1.核心线程数3.2.最大线程数3.3.队列容量3.4.时间参数3.5.拒绝策略4.参数设置建议正文:【Java 线程池简介】Java 线程池(ExecutorService)是Java 并发编程中的一个重要工具,它允许程序控制线程的创建、管理和调度。

通过使用线程池,可以避免手动创建和管理线程带来的复杂性和资源浪费,提高程序的运行效率和稳定性。

【Java 线程池的参数】在创建线程池时,需要配置一系列参数,这些参数决定了线程池的运行行为和性能。

下面我们将详细介绍这些参数。

【参数详解】1.核心线程数(corePoolSize):线程池中始终存在的线程数量。

当线程池创建后,这些线程将被立即初始化,即使它们没有被任务使用。

如果任务数量超过核心线程数,线程池将创建新的线程来处理这些任务。

默认值为0,表示线程池中不保留任何空闲线程。

2.最大线程数(maxPoolSize):线程池中允许存在的最大线程数量。

当任务数量超过核心线程数且队列已满时,线程池将创建新的线程来处理这些任务,但线程数量不会超过这个参数的值。

默认值为Integer.MAX_VALUE,表示线程池允许无限制地创建线程。

3.队列容量(queueCapacity):线程池中的任务队列可以容纳的最大任务数量。

当线程池中的线程数量达到最大值且队列已满时,新的任务将无法加入队列,直到队列中有空闲空间。

默认值为10,表示队列容量为10。

4.时间参数(keepAliveTime,timeUnit):线程池中空闲线程的存活时间。

当线程池中的任务数量少于核心线程数时,空闲线程将等待任务,最多等待的时间由这个参数决定。

默认值为60 秒,时间单位为秒(SECONDS)。

5.拒绝策略(rejectedExecutionHandler):当线程池无法处理任务时,可以采取的策略。

executorservice设置合理的线程池数量

在使用`ExecutorService` 时,合理设置线程池的数量是一个重要的考虑因素。

线程池的数量取决于多个因素,包括任务的类型、系统的硬件资源、应用程序的需求以及预期的负载。

以下是一些指导原则,帮助你设置合理的线程池数量:1. 任务类型:-CPU密集型任务:这类任务需要大量的计算资源,通常线程数设置为CPU核心数加1可以获得较好的性能,因为线程数超过CPU核心数时,CPU缓存共享和上下文切换可能会导致性能下降。

-I/O密集型任务:这类任务通常会等待外部资源,如网络请求或数据库响应。

在这种情况下,可以设置更多的线程来提高I/O操作的并发性,以充分利用系统资源。

2. 系统资源:- CPU核心数:如前所述,线程数通常不会超过CPU的核心数,以避免过多的上下文切换和缓存共享问题。

-内存大小:内存资源也会影响线程池的大小。

过多的线程可能会消耗过多的内存,导致系统性能下降。

3. 应用程序需求:-响应时间:如果应用程序需要快速响应,可能需要更多的线程来提高并发处理能力。

-吞吐量:如果注重处理大量任务,可能需要平衡线程数以提高吞吐量。

4. 预期负载:-峰值负载:在预期的高峰负载期间,可能需要增加线程池的大小,以应对增加的任务量。

-长期负载:对于长期存在的负载,需要根据任务的性质和系统资源来确定一个合理的线程池大小。

5. 经验和测试:-历史数据:参考过去类似任务的表现,可以提供设置线程池的线索。

-压力测试:通过模拟高负载情况进行测试,可以帮助确定线程池的大小是否合理。

在实际应用中,通常会使用一些工具和方法来估算和调整线程池的大小,例如,使用JMH(Java Microbenchmark Harness)进行性能测试,或者使用基于观察和经验的方法来调整线程池参数。

总之,设置合理的线程池数量需要综合考虑多个因素,并根据实际情况进行调整。

正确的线程池大小可以帮助你优化应用程序的性能,提高资源利用率。

多线程execute和submit区别和使用

多线程execute和submit区别和使⽤在Java5之后,并发线程这块发⽣了根本的变化,最重要的莫过于新的启动、调度、管理线程的⼀⼤堆API了。

在Java5以后,通过Executor 来启动线程⽐⽤Thread的start()更好。

在新特征中,可以很容易控制线程的启动、执⾏和关闭过程,还可以很容易使⽤线程池的特性。

⼀、创建任务任务就是⼀个实现了Runnable接⼝的类。

创建的时候实run⽅法即可。

⼆、执⾏任务通过java.util.concurrent.ExecutorService接⼝对象来执⾏任务,该接⼝对象通过⼯具类java.util.concurrent.Executors的静态⽅法来创建。

Executors此包中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的⼯⼚和实⽤⽅法。

ExecutorService提供了管理终⽌的⽅法,以及可为跟踪⼀个或多个异步任务执⾏状况⽽⽣成 Future 的⽅法。

可以关闭 ExecutorService,这将导致其停⽌接受新任务。

关闭后,执⾏程序将最后终⽌,这时没有任务在执⾏,也没有任务在等待执⾏,并且⽆法提交新任务。

executorService.execute(new TestRunnable());1、创建ExecutorService通过⼯具类java.util.concurrent.Executors的静态⽅法来创建。

Executors此包中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的⼯⼚和实⽤⽅法。

⽐如,创建⼀个ExecutorService的实例,ExecutorService实际上是⼀个线程池的管理⼯具:ExecutorService executorService = Executors.newCachedThreadPool();ExecutorService executorService = Executors.newFixedThreadPool(3);ExecutorService executorService = Executors.newSingleThreadExecutor();2、将任务添加到线程去执⾏当将⼀个任务添加到线程池中的时候,线程池会为每个任务创建⼀个线程,该线程会在之后的某个时刻⾃动执⾏。

executorservice 的方法

ExecutorService是Java中的一个接口,它是线程池的核心接口,用于管理和调度线程的执行。

ExecutorService接口继承自Executor接口,并在其基础上提供了一些额外的方法。

以下是ExecutorService接口的一些常用方法:1. submit(Runnable task):提交一个Runnable任务给线程池执行,并返回一个表示任务结果的Future对象。

2. submit(Callable<T> task):提交一个Callable任务给线程池执行,并返回一个表示任务结果的Future对象。

3. shutdown():平缓地关闭线程池,不再接受新的任务提交,但会等待已经提交的任务执行完成。

4. shutdownNow():立即关闭线程池,尝试中断正在执行的任务,并返回尚未执行的任务列表。

5. isShutdown():判断线程池是否已经关闭。

6. isTerminated():判断线程池是否已经终止,即所有任务都已经执行完成。

7. awaitTermination(long timeout, TimeUnit unit):等待线程池终止,最多等待指定的时间。

8. invokeAny(Collection<? extends Callable<T>> tasks):执行给定的任务集合中的一个任务,并返回其中一个任务的结果,如果其中一个任务成功完成(未抛出异常),则返回该任务的结果。

9. invokeAll(Collection<? extends Callable<T>> tasks):执行给定的任务集合中的所有任务,并返回一个包含所有任务结果的Future列表。

10. execute(Runnable command):提交一个Runnable任务给线程池执行,不返回任务结果。

这些方法可以通过ExecutorService对象调用,用于管理和控制线程池中的任务执行。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

android线程池的理解,晚上在家无事预习了一下android异步加载的例子,也学习到了一个很重要的东东那就是线程池+缓存下面看他们的理解。

[size=1.8em]Handler+Runnable模式我们先看一个并不是异步线程加载的例子,使用Handler+Runnable模式。

这里为何不是新开线程的原因请参看这篇文章:Android Runnable 运行在那个线程这里的代码其实是在UI 主线程中下载图片的,而不是新开线程。

我们运行下面代码时,会发现他其实是阻塞了整个界面的显示,需要所有图片都加载完成后,才能显示界面。

?代码片段,双击复制0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0 1 1 1 2 1package ghj1976.AndroidTest;import java.io.IOException;import .URL;import android.app.Activity;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.os.Handler;import android.os.SystemClock;import android.util.Log;import android.widget.ImageView;publicclass MainActivity extends Activity {@Overridepublicvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.main);loadImage("/img/baidu_logo.gif", R.id.imageView1);loadImage(<imgid="\"aimg_7Va0b\""onclick="\"zoom(this,"this.src,=""0,=""0)\"="" class="\"zoom\""file="\"/images/logo_new.gif\"" onmouseover="\"img_onmouseoverfunc(this)\""onload="\"thumbImg(this)\"" border="\"0\"" alt="\"\"" src="\"/images/logo_new.gif\"" lazyloaded="true">",R.id.imageView2);loadImage("/30d/img/web/logo.gif, R.id.imageView3);loadImage("/www/images/csdnindex_logo.gif",R.id.imageView4);loadImage("/logo_small.gif",3 14 15 16 17 18 19 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 R.id.imageView5);}private Handler handler =new Handler();privatevoid loadImage(final String url,finalint id) {handler.post(new Runnable() {publicvoid run() {Drawable drawable =null;try{drawable = Drawable.createFromStream(new URL(url).openStream(),"image.gif");}catch(IOException e) {Log.d("test", e.getMessage());}if(drawable ==null) {Log.d("test","null drawable");}else{Log.d("test","not null drawable"); }// 为了测试缓存而模拟的网络延时SystemClock.sleep(2000);((ImageView)MainActivity.this.findViewById(id)).setImageDrawable(drawable );}});}}536373839441424344454647484955152Handler+Thread+Message模式这种模式使用了线程,所以可以看到异步加载的效果。

核心代码:?package ghj1976.AndroidTest;代码片段,双击复制0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1import java.io.IOException;import .URL;import android.app.Activity;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.os.SystemClock;import android.util.Log;import android.widget.ImageView;publicclass MainActivity extends Activity {@Overridepublicvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.main);loadImage2("/img/baidu_logo.gif", R.id.imageView1);loadImage2("/images/logo_new.gif",R.id.imageView2);loadImage2("/30d/img/web/logo.gif", R.id.imageView3);loadImage2("/www/images/csdnindex_logo.gif",R.id.imageView4);loadImage2("/logo_small.gif", R.id.imageView5);}final Handler handler2 =new Handler() {@Overridepublicvoid handleMessage(Message msg) {((ImageView)MainActivity.this.findViewById(msg.arg1)).setImageDrawable((Drawable) msg.obj);}};// 采用handler+Thread模式实现多线程异步加载privatevoid loadImage2(final String url,finalint id) {Thread thread =new Thread() {@Override9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3 6 3 7 3 8 3 9 4 0 4publicvoid run() {Drawable drawable =null;try{drawable = Drawable.createFromStream(new URL(url).openStream(),"image.png");}catch(IOException e) {Log.d("test", e.getMessage());}// 模拟网络延时SystemClock.sleep(2000);Message message = handler2.obtainMessage(); message.arg1 = id;message.obj = drawable;handler2.sendMessage(message);}};thread.start();thread =null;}}4 2 4 3 4 4 45 46 47 48 49 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5 8 5 9 6 0 6 1 6 2 6这时候我们可以看到实现了异步加载,界面打开时,五个Im ageView都是没有图的,然后在各自线程下载完后才把图自动更新上去。

Handler+ExecutorService(线程池)+MessageQueue模式能开线程的个数毕竟是有限的,我们总不能开很多线程,对于手机更是如此。

这个例子是使用线程池。

Android拥有与Java相同的ExecutorServi ce实现,我们就来用它。

线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。

当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。

线程池的信息可以参看这篇文章:Java&Android的线程池-ExecutorServi ce 下面的演示例子是创建一个可重用固定线程数的线程池。

核心代码?代码片段,双击复制0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0 package ghj1976.AndroidTest;import java.io.IOException;import .URL;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import android.app.Activity;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.os.SystemClock;import android.util.Log;import android.widget.ImageView;publicclass MainActivity extends Activity {@Overridepublicvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.main);loadImage3("/img/baidu_logo.gif", R.id.imageView1);loadImage3("/images/logo_new.gif",R.id.imageView2);loadImage3("/30d/img/web/logo.gif", R.id.imageView3);1 1 12 13 14 15 16 17 18 19 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 loadImage3("/www/images/csdnindex_logo.gif",R.id.imageView4);loadImage3("/logo_small.gif",R.id.imageView5);}private Handler handler =new Handler();private ExecutorService executorService = Executors.newFixedThreadPool(5);// 引入线程池来管理多线程privatevoid loadImage3(final String url,finalint id) {executorService.submit(new Runnable() {publicvoid run() {try{final Drawable drawable = Drawable.createFromStream(new URL(url).openStream(),"image.png");// 模拟网络延时SystemClock.sleep(2000);handler.post(new Runnable() {publicvoid run() {((ImageView) MainActivity.this.findViewById(id)).setIm ageDrawable(drawable);}});}catch(Exception e) {thrownew RuntimeException(e);}}});}}3 34 35 36 37 38 39 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 45565758这里我们象第一步一样使用了handler.post(new Runnable() { 更新前段显示当然是在UI主线程,我们还有executorService.subm it(new Runnable() { 来确保下载是在线程池的线程中。

相关文档
最新文档