Android第二周作业:
利用HttpUrlConnection,线程池,单例模式还有建造者模式写一个网络请求工具类。
- 要求:
- 首先先去学习什么是线程池,明白四种线程池的作用是什么,比直接开线程好在哪里,然后选择合适的来写;
- 学习建造者模式(或者叫做Builder模式),在写的时候利用其来配置参数(理解为什么要用builder模式);
- 学习单例模式,因为这个网络请求工具类不用单例模式的话不是就会创建很多线程池吗?单例模式有很多个,都去看看,记得选个合适哦。
HttpUrlConnection
在Android开发中网络请求是最常用的操作之一, Android SDK中对HTTP(超文本传输协议)也提供了很好的支持,这里包括两种接口:
- 标准Java接口(java.NET) —-HttpURLConnection,可以实现简单的基于URL请求、响应功能;
- Apache接口(org.appache.http)—-HttpClient,使用起来更方面更强大。
但在android API23的SDK中Google将HttpClient移除了。Google建议使用httpURLconnection进行网络访问操作。
HttpURLconnection是基于http协议的,支持get,post,put,delete等各种请求方式,最常用的就是get和post。
线程池
笔记出处:(掘金)简单理解Java四种线程池(这个也是红岩的一个干事写的哈哈哈!好巧哦ovo)
(bilibili)1小时搞清楚Java线程池原理(P1~P6)
1、线程(Thread)
线程是计算机调度的最小单位是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
2、多线程
- 当我们没有接触线程前,我们的程序都是执行在主线程中的。当大家需要考虑到线程问题的时候一般是需要进行耗时操作的时候,比如网络请求等。把网络请求放在主线程中会导致主线程被迫等待这个任务结束完后才能继续,可能会对性能造成影响。
- 解决方案是:新开一个线程来完成这个任务,新开线程主要有三种方法,一种是继承Thread类,一种是实现Runnable接口,还有就是实现Callable接口。
3、线程池
- 因为如果一个任务就新开一个线程的话对系统的开销非常大,如果频繁地开新的任务但是每个任务又只需要很短的时间无疑会加重系统的负担,比如服务器回应用户的登录请求。
- Java封装的线程池为这种现象提供了解决方案,它主要通过一个等待队列的设置来实现,比如我的线程池大小为5,然而现在5个线程都在运行中,那么这时候再提交一个新的任务就会被放在等待队列,当任何一个线程中的任务执行完毕后再进行。
4、JDK-5 Executor 框架
在 Java 5 之后,并发编程引入了一堆新的启动、调度和管理线程的API。Executor 框架便是 Java 5 中引入的,其内部使用了线程池机制,它在 java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在 Java 5之后,通过 Executor 来启动线程比使用 Thread 的 start 方法更好,更易管理,效率更好(用线程池实现,节约开销),还有助于避免 this 逃逸问题。
Executor 框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable 等。
4.1 newCachedThreadPool 缓存线程池
public static ExecutorService newCachedThreadPool();
顾名思义,这是一个具有缓存特性的线程池:
- 先检查这个线程池中有没有闲置(IDLE)的线程,如果有那就把新任务放入这个线程中进行,如果没有那就新开一个线程加入池中并执行新任务。
- 闲置的默认时间是60s,超过了这个时间如果没有新的任务使用这个线程,那么这个线程将被销毁。
4.2 newFixedThreadPool 核心线程池
public static ExecutorService newFixedThreadPool(int corePoolSize);
实际上核心线程池和缓存线程池在系统底层实际上是一样的,只是参数不一致,线程池中的线程数量固定,且IDLE为0;
- 和缓存线程池一样,优先使用闲置的线程,不过最多只能有corePoolSize数量的线程同时存在。
- 如果有线程池已满且有新任务加入,则进入缓冲队列。
4.3 newScheduledThreadPool 调度线程池
public static ScheduledExecutorService new ScheduledThreadPool(int corePoolSize)
该线程池内的线程可以调度(推迟/周期)。
4.4 newSingleThreadExecutor 单例线程池
public static ExecutorService newSingleThreadExecutor();
单例线程池,只含有一个线程。
- 和缓存线程池同样的底层实现,也只是参数不同,线程数目是1,IDLE是0s。
5. 总结
一般来说,CachedTheadPool 在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此它是合理的 Executor 的首选,只有当这种方式会引发问题时(比如需要大量长时间面向连接的线程时),才需要考虑用 FixedThreadPool。 ——《Thinking in Java》
建造者模式
1、模式概述
- 将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
2、builder模式的4个角色
- Director: 决定如何构建最终产品的算法。其会包含一个负责组装的方法void Construct(Builder builder)。在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的 getProduct() 方法获得最终的产品。
- Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct()。
- ConcreteBuilder: Builder的实现类。
- Product: 最终要生成的对象,例如 Computer实例。
3、为什么要用builder模式?builder模式优点
- 可以对产品内部表示进行改变,将构造代码和表示代码相分离。
1)封装性:使用建造者模式可以是客户端不必知道产品内部组成的细节。
2)建造者独立,容易扩展。例如xxBuilder和xxxBuilder是相互独立的,对系统扩展非常有利。
3)便于控制细节风险:由于具体的建造者是独立的,因此可以对建造者过程逐步细化,而不对其他的模块产生任何影响。
单例模式
1、单例模式的优点
- 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的创建、销毁时,而且创建或销毁时性能无法优化,单例模式的优势就非常明显。
- 由于单例模式生成一个实例,所以减少了系统性能的开销,当一个对象的产生需要比较多的资源时,可以通过在应用启动时直接生产一个单例对象,然后用永远驻留内存的方式来解决。
- 单例模式可以避免对一个资源的多重占用。
- 单例模式可以在系统设置全局的访问点、优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。
2、单例模式的使用场景
在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现“不良反应”,可以采用单例模式,具体的场景如下:
- 要求生成唯一序列号的环境;
- 在整个项目中需要一个共享访问点或共享数据,例如一个Web上的计数器,可以不用每次把刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
- 创建一个对象需要消耗资源过多,如要访问IO和数据库等资源;
- 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式)。