2018年度最新Java面试题'整编汇总.doc

上传人:小** 文档编号:805143 上传时间:2019-07-16 格式:DOC 页数:36 大小:500KB
返回 下载 相关 举报
2018年度最新Java面试题'整编汇总.doc_第1页
第1页 / 共36页
2018年度最新Java面试题'整编汇总.doc_第2页
第2页 / 共36页
点击查看更多>>
资源描述

《2018年度最新Java面试题'整编汇总.doc》由会员分享,可在线阅读,更多相关《2018年度最新Java面试题'整编汇总.doc(36页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、1 1 基础篇基础篇1.11.1 基本功基本功1.1.11.1.1面向对象特征面向对象特征封装,继承,多态和抽象 1、 封装 封装给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方 法来改变它内部的数据。在 Java 当中,有 3 种修饰符: public, private 和 protected。每一种修饰符给其他的位于同一个包或者不同包下面对象赋予了不同的访 问权限。下面列出了使用封装的一些好处: 1)通过隐藏对象的属性来保护对象内部的状态。 2)提高了代码的可用性和可维护性,因为对象的行为可以被单独的改变或者是扩展 。 3)禁止对象之间的不良交互提高模块化 2、 继承

2、 继承给对象提供了从基类获取字段和方法的能力。继承提供了代码的重用行,也可以 在不修改类的情况下给现存的类添加新特性。 3、 多态 多态是编程语言给不同的底层数据类型做相同的接口展示的一种能力。一个多态类型 上的操作可以应用到其他类型的值上面。 4、 抽象 抽象是把想法从具体的实例中分离出来的步骤,因此,要根据他们的功能而不是实现 细节来创建类。 Java 支持创建只暴漏接口而不包含方法实现的抽象的类。这种抽象技术的主要目的是把类 的行为和实现细节分离开。1.1.21.1.2final,final, finally,finally, finalizefinalize 的区别的区别1、 fina

3、l修饰符(关键字) 如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。 因此一个类不能既被声明为 abstract的,又被声明为final的。 将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量 必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方 法也同样只能使用,不能重载。2、 finally 在异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。3、 finalize 方法名。Java

4、技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃 圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。1.1.31.1.3intint 和和 IntegerInteger 有什么区别有什么区别int是基本数据类型 ,而Integer是其包装类,注意是一个类。 为什么要提供包装类呢? 一是为了在各种类型间转化,通过各种方法的调用。否则你无

5、法直接通过变量转化。1.1.41.1.4重载和重写的区别重载和重写的区别override(重写)1. 方法名、参数、返回值相同。2. 子类方法不能缩小父类方法的访问权限。3. 子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。4. 存在于父类和子类之间。5. 方法被定义为final不能被重写。 overload(重载)1. 参数类型、个数、顺序至少有一个不相同。2. 不能重载只有返回值不同的方法名。3. 存在于父类和子类、同类中。区别点重载重写(覆写)英文OverloadingOveriding定义方法名称相同,参数的类型或个数 不同方法名称、参数类型、返回值类型全部相 同权限

6、对权限没要求被重写的方法不能拥有更严格的权限范围发生在一个类中发生在继承类中1.1.51.1.5抽象类和接口有什么区别抽象类和接口有什么区别接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可 以有私有方法或私有变量的,另外,实现接口的一定要实现接口里定义的所有方法,而实 现抽象类可以有选择地重写需要用到的方法,一般的应用里,最顶级的是接口,然后是抽 象类实现接口,最后才到具体类实现。 还有,接口可以实现多重继承,而一个类只能继承一个超类,但可以通过继承多个接 口实现多重继承,接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面 的变量全是常量)的作用。1

7、.1.61.1.6说说反射的用途及实现说说反射的用途及实现Java反射机制主要提供了以下功能:在运行时构造一个类的对象;判断一个类所具有 的成员变量和方法;调用一个对象的方法;生成动态代理。反射最大的应用就是框架 Java反射的主要功能: - 确定一个对象的类 - 取出类的modifiers,数据成员,方法,构造器,和超类. - 找出某个接口里定义的常量和方法说明. - 创建一个类实例,这个实例在运行时刻才有名字(运行时间才生成的对象). - 取得和设定对象数据成员的值,如果数据成员名是运行时刻确定的也能做到. - 在运行时刻调用动态对象的方法. - 创建数组,数组大小和类型在运行时刻才确定,

8、也能更改数组成员的值. 反射的应用很多,很多框架都有用到 spring 的 ioc/di 也是反射. javaBean和jsp之间调用也是反射. struts的 FormBean 和页面之间也是通过反射调用. JDBC 的 classForName()也是反射. hibernate的 find(Class clazz) 也是反射. 反射还有一个不得不说的问题,就是性能问题,大量使用反射系统性能大打折扣。怎么使 用使你的系统达到最优就看你系统架构和综合使用问题啦,这里就不多说了。 来源:http:/ 提到注解就不能不说反射,Java自定义注解是通过运行时靠反射获取注解。 实际开发中,例如我们要获

9、取某个方法的调用日志,可以通过AOP(动态代理机制)给 方法添加切面,通过反射来获取方法包含的注解,如果包含日志注解,就进行日志记录。1.1.81.1.8HTTPHTTP 请求的请求的 GETGET 与与 POSTPOST 方式的区别方式的区别1、 请求数据的方式 GET请求,请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用 成功加载后,会将Driver类的实例注册到DriverManager类中。 2、 提供JDBC连接的URL - 连接URL定义了连接数据库时的协议、子协议、数据源标识。 - 书写形式:协议:子协议:数据源标识 协议:在JDBC中总是以jdbc开始 子协议

10、:是桥连接的驱动程序或是数据库管理系统名称。数据源标识:标记找到数据库来 源的地址与连接端口。 例如: /MySql的连接URL,true表示使用Unicode字符集, characterEncoding字符编码方式。jdbc:mysql:/localhost:3306/test?useUnicode=true 3、创建数据库的连接 - 要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象, 该对象就代表一个数据库的连接。 - 使用DriverManager的getConnectin(String url , String username , S

11、tring password )方法传入指定的欲连接的数据库的路径、数据库的用户名和 密码来获得。 例如: /连接MySql数据库,用户名和密码都是rootString url = “jdbc:mysql:/localhost:3306/test“; Connection con = DriverManager.getConnection(url, “root“,“root“) 4、 创建一个Statement,要执行SQL语句,必须获得java.sql.Statement实例,Statement 实例分为以下3 种类型: 1)执行静态SQL语句。通常通过Statement实例实现。State

12、ment stmt = con.createStatement() ; 2)执行动态SQL语句。通常通过PreparedStatement实例实现。PreparedStatement pstmt = con.prepareStatement(sql) ; 3)执行数据库存储过程。通常通过CallableStatement实例实现。 CallableStatement cstmt = con.prepareCall(“CALL demoSp(? , ?)”) ; 5、 执行SQL语句 提供了三种执行SQL语句的方法:executeQuery 、executeUpdate 和execute 1)R

13、esultSet executeQuery(String sqlString):执行查询数据库的SQL语句 ,返回一个结果集(ResultSet)对象。 2)int executeUpdate(String sqlString):用于执行INSERT、UPDATE或 DELETE语句以及SQL DDL语句,如:CREATE TABLE和DROP TABLE等 3)execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合的 语句。 6、 处理结果: 1)执行更新返回的是本次操作影响到的记录数。 2)执行查询返回的结果是一个ResultSet对象。 ResultSet包

14、含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这 些行中数据的访问(列是从左到右编号的,并且从列1开始)。 使用结果集(ResultSet)对象的访问方法获取数据: while(rs.next() String name = rs.getString(“name”) ; String pass = rs.getString(1) ; / 此方法比较高效 7、 关闭JDBC对象 操作完成以后要把所有使用的JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声明 顺序相反: 1)关闭记录集rs.close() 2)关闭声明stmt.close() 3)关闭连接对象conn.clo

15、se()1.1.111.1.11 MVCMVC 设计思想设计思想M:Model 模型 V:View 视图 C:Controller 控制器 模型就是封装业务逻辑和数据的一个一个的模块, 控制器就是调用这些模块的(java中通常是用Servlet来实现,框架的话很多是用Struts2来 实现这一层), 视图就主要是你看到的,比如JSP等。 当用户发出请求的时候,控制器根据请求来选择要处理的业务逻辑和要选择的数据,再返回 去把结果输出到视图层,这里可能是进行重定向或转发等.1.1.121.1.12 equalsequals 与与 = 的区别的区别值类型(int,char,long,boolean等

16、)都是用=判断相等性。 对象引用的话,=判断引用所指的对象是否是同一个。 equals是Object的成员函数,有些类会覆盖(override)这个方法,用于判断对象的 等价性。 例如String类,两个引用所指向的String都是”abc”,但可能出现他们实际对应的对 象并不是同一个(和jvm实现方式有关),因此用=判断他们可能不相等,但用equals判断一定是相等的。1.21.2 集合集合1.2.11.2.1 ListList 和和 SetSet 区别区别List,Set都是继承自Collection接口 List特点:元素有放入顺序,元素可重复 Set特点:元素无放入顺序,元素不可重复,

17、重复元素会覆盖掉 (注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其 位置其实是固定的,加入Set的Object必须定义equals()方法,另外list支持for循环,也 就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来 取得想要的值。) Set和List对比: Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会 引起其他元素位置改变。1.2.21.2.2 ListList 和和 MapMap 区别区别Li

18、st是对象集合,允许对象重复。 Map是键值对的集合,不允许key重复。1.2.31.2.3 ArraylistArraylist 与与 LinkedListLinkedList 区别区别ArraylistArraylist: 优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了, 查询操作效率会比较高(在内存里是连着放的)。 缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。 LinkedListLinkedList: 优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要 等一个连续的地址

19、,对于新增和删除操作add和remove,LinedList比较占优势。LinkedLis t 适用于要头尾操作或插入指定位置的场景 缺点:因为LinkedList要移动指针,所以查询操作性能比较低。 适用场景分析: 当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改 时采用LinkedList。1.2.41.2.4 ArrayListArrayList 与与 VectorVector 区别区别/构造一个初始容量为10的空列表public ArrayList() /构造一个具有指定初始容量的空列表。public ArrayList(int initialC

20、apacity) /构造一个包含指定 collection 的元素的列表public ArrayList(Collection c)Vector有四个构造方法: /使用指定的初始容量和等于零的容量增量构造一个空向量public Vector() /构造一个空向量,使其内部数据数组的大小,其标准容量增量为零public Vector(int initialCapacity) /构造一个包含指定 collection 中的元素的向量public Vector(Collection c) /使用指定的初始容量和容量增量构造一个空的向量public Vector(int initialCapacity

21、,int capacityIncrement) ArrayList和Vector都是用数组实现的,主要有这么三个区别: Vector是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不确定的结果。 而ArrayList不是,这个可以从源码中看出,Vector类中的方法很多有synchronized进行修 饰,这样就导致了Vector在效率上无法与ArrayList相比; 两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不 同。 Vector可以设置增长因子,而ArrayList不可以。 Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。

22、 适用场景分析: Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。 如果不考虑到线程的安全因素,一般用ArrayList效率比较高。 如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据 ,用Vector有一定的优势。1.2.51.2.5 HashMapHashMap和和HashtableHashtable的区别的区别1.hashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKe y()方法。 2.hashTable同步的,而HashMap是非同步的,效率上

23、逼hashTable要高。 3.hashMap允许空键值,而hashTable不允许。 注意: TreeMap:非线程安全基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态 。 Treemap:适用于按自然顺序或自定义顺序遍历键(key)。 参考:http:/ HashSetHashSet 和和 HashMapHashMap 区别区别set是线性结构,set中的值不能重复,hashset是set的hash实现,hashset中值不能重 复是用hashmap的key来实现的。 map是键值对映射,可以空键空值。HashMap是Map接口的hash实现,key的唯一性是通 过key

24、值hash值的唯一来确定,value值是则是链表结构。 他们的共同点都是hash算法实现的唯一性,他们都不能持有基本类型,只能持有对象1.2.71.2.7 HashMapHashMap 和和 ConcurrentHashMapConcurrentHashMap 的区别的区别ConcurrentHashMap是线程安全的HashMap的实现。(1)ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都 用lock锁进行保护,相对于HashTable的syn关键字锁的粒度更精细了一些,并发性能更好 ,而HashMap没有锁机制,不是线程安全的。 (2)

25、HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。1.2.81.2.8 HashMapHashMap 的工作原理及代码实现的工作原理及代码实现简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数 组位置上的链表中的存储位置; 当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再

26、根据equa ls方法从该位置上的链表中取出该Entry。Fail- Fast机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进 行操作时,就可能会产生 fail-fast 事件。 例如:当某一个线程A通过 iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集 合时,就会抛出 ConcurrentModificationException异常,产生 fail-fast 事件。 参考:https:/tracylihui.github.io/2015/07/01/Java集合学习1:HashMap的实现原理1.2.91.2

27、.9 ConcurrentHashMapcurrentHashMap 的工作原理及代码实现的工作原理及代码实现HashTable里使用的是synchronized关键字,这其实是对对象加锁,锁住的都是对象整 体,当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长 的时间。ConcurrentHashMap算是对上述问题的优化,其构造函数如下,默认传入的是16, 0.75,16。ConcurrentHashMap引入了分割(Segment),上面代码中的最后一行其实就可以理解为 把一个大的Map拆分成N个小的HashTable,在put方法中,会根据hash(p

28、aramK.hashCode() 来决定具体存放进哪个Segment,如果查看Segment的put操作,我们会发现内部使用的同步 机制是基于lock操作的,这样就可以对Map的一部分(Segment)进行上锁,这样影响的只 是将要放入同一个Segment的元素的put操作,保证同步的时候,锁住的不是整个Map(Hash Table就是这么做的),相对于HashTable提高了多线程环境下的性能,因此HashTable已经 被淘汰了。1.31.3 线程线程1.3.11.3.1 创建线程的方式及实现创建线程的方式及实现Java中创建线程主要有三种方式: 一、继承Thread类创建线程类 (1)定

29、义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完 成的任务。因此把run()方法称为执行体。 (2)创建Thread子类的实例,即创建了线程对象。 (3)调用线程对象的start()方法来启动该线程。 二、通过Runnable接口创建线程类 (1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样 是该线程的线程执行体。 (2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对 象才是真正的线程对象。 (3)调用线程对象的start()方法来启动该线程

30、。 三、通过Callable和Future创建线程 (1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体, 并且有返回值。 (2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask 对象封装了该Callable对象的call()方法的返回值。 (3)使用FutureTask对象作为Thread对象的target创建并启动新线程。 (4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值创建线程的三种方式的对比 采用实现Runnable、Callable接口的方式创见

31、多线程时,优势是: 线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。 在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面 向对象的思想。 劣势是: 编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。 使用继承Thread类的方式创建多线程时优势是: 编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用t his即可获得当前线程。 劣势是: 线程类已经继承了Th

32、read类,所以不能再继承其他父类。1.3.21.3.2 sleep()sleep() 、joinjoin()、()、yieldyield()有什么区别()有什么区别1 1、sleep()sleep()方法方法 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调 度程序精度和准确性的影响。让其他线程有机会继续执行,但它并不释放对象锁。也就是 如果有Synchronized同步块,其他线程仍然不能访问共享数据。注意该方法要捕获异常 比如有两个线程同时执行(没有Synchronized),一个线程优先级为MAX_PRIORITY,另一个 为MIN_PRIORITY,如果

33、没有Sleep()方法,只有高优先级的线程执行完成后,低优先级的线 程才能执行;但当高优先级的线程sleep(5000)后,低优先级就有机会执行了。 总之,sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级 的线程有执行的机会。 2 2、yield()yield()方法方法yield()方法和sleep()方法类似,也不会释放“锁标志”,区别在于,它没有参数,即yie ld()方法只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可 执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行 机会,这也和sle

34、ep()方法不同。 3 3、join()join()方法方法 Thread的非静态方法join()让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之 前,B不能工作。Thread t = new MyThread(); t.start(); t.join(); 保证当前线程停止执行,直到该线程所加入的线程完成为止。然而,如果它加入的线程没 有存活,则当前线程不需要停止。1.3.31.3.3 说说说说 CountDownLatchCountDownLatch 原理原理CountDownLatch是同步工具类之一,可以指定一个计数值,在并发环境下由线程进行减1操 作,当计数值变为0之后,被

35、await方法阻塞的线程将会唤醒,实现线程间的同步。1、构造器。构造函数很简单地传递计数值给Sync,并且设置了state。2、 阻塞线程。await方法,直接调用了AQS(即Sync)的acquireSharedInterruptibly首先尝试获取共享锁,实现方式和独占锁类似,由CountDownLatch实现判断逻辑。返回1代表获取成功,返回- 1代表获取失败。如果获取失败,需要调用doAcquireSharedInterruptibly:doAcquireSharedInterruptibly的逻辑和独占功能具体如下: 1)创建的Node是定义成共享的(Node.SHARED); 2)

36、被唤醒后重新尝试获取锁,不只设置自己为head,还需要通知其他等待的线程。(重 点看后文释放操作里的setHeadAndPropagate)3、 释放操作。countDown操作实际就是释放锁的操作,每调用一次,计数值减少1。同样是首先尝试释放锁,具体实现在CountDownLatch中:死循环加上cas的方式保证state的减1操作,当计数值等于0,代表所有子线程都执行完毕 ,被await阻塞的线程可以唤醒了,下一步调用doReleaseShared:标记1里,头节点状态如果SIGNAL,则状态重置为0,并调用unparkSuccessor唤醒下个节点 。 标记2里,被唤醒的节点状态会重置成

37、0,在下一次循环中被设置成PROPAGATE状态,代表状 态要向后传播。参考: 分析CountDownLatch的实现原理 什么时候使用CountDownLatch Java并发编程:CountDownLatch、CyclicBarrier和Semaphore1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;另外,CountDownLatch是不能够重用的,而

38、CyclicBarrier是可以重用的。2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。1.3.41.3.4 说说说说 CyclicBarrierCyclicBarrier 原理原理参考: JUC回顾之-CyclicBarrier底层实现和原理1.3.51.3.5 说说说说 SemaphoreSemaphore 原理原理JAVA多线程信号量(Semaphore) JUC回顾之-Semaphore底层实现和原理1.3.61.3.6 说说说说 ExchangerExchanger 原理原理java.util.concurrent.Exchanger应用范例与原理浅析1.

39、3.71.3.7 说说说说 CountDownLatchCountDownLatch 与与 CyclicBarrierCyclicBarrier 区别区别CountDownLatchCyclicBarrier减计数方式加计数方式计算为0时释放所有等待的线程计数达到指定值时释放所有等待线程计数为0时,无法重置计数达到指定值时,计数置为0重新开始调用countDown()方法计数减一,调用await() 方法只进行阻塞,对计数没任何影响调用await()方法计数加1,若加1后的值 不等于构造方法的值,则线程阻塞不可重复利用可重复利用尽量把CyclicBarrier和CountDownLatch的区

40、别说通俗点1.3.81.3.8 ThreadLocalThreadLocal 原理分析原理分析ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避 免参数传递的方便的对象访问方式。归纳了两点: 1)每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持 到其中,各管各的,线程可以正确的访问到自己的对象。 2)将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程 的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的ge t()方法取得自己线程保存的那个对象,避

41、免了将这个对象作为参数传递的麻烦。Java并发编程:深入剖析ThreadLocal1.3.91.3.9 讲讲线程池的实现原理讲讲线程池的实现原理线程池的具体实现原理,将从下面几个方面讲解: 1. 线程池状态 1)当创建线程池后,初始时,线程池处于RUNNING状态; 2)如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能 够接受新的任务,它会等待所有任务执行完毕; 3)如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接 受新的任务,并且会去尝试终止正在执行的任务; 4)当线程池处于SHUTDOWN或STOP状态,并且所有工作线

42、程已经销毁,任务缓存 队列已经清空或执行结束后,线程池被设置为TERMINATED状态。 2. 任务的执行 1)首先,要清楚corePoolSize和maximumPoolSize的含义; 2)其次,要知道Worker是用来起到什么作用的; 3)要知道任务提交给线程池之后的处理策略,这里总结一下主要有4点: 如果当前线程池中的线程数目小于corePoolSize,则每来一个任务,就会创 建一个线程去执行这个任务; 如果当前线程池中的线程数目=corePoolSize,则每来一个任务,会尝试将 其添加到任务缓存队列当中,若添加成功,则该任务会等待空闲线程将其取 出去执行;若添加失败(一般来说是任

43、务缓存队列已满),则会尝试创建新 的线程去执行这个任务; 如果当前线程池中的线程数目达到maximumPoolSize,则会采取任务拒绝策略 进行处理; 如果线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止, 直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程 设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会 被终止。 3. 线程池中的线程初始化 默认情况下,创建线程池之后,线程池中是没有线程的,需要提交任务之后才会 创建线程。在实际中如果需要线程池创建之后立即创建线程

44、,可以通过以下两个 方法办到: prestartCoreThread():初始化一个核心线程; prestartAllCoreThreads():初始化所有核心线程 注意上面传进去的参数是null,如果传进去的参数为null,则最后执行线程会阻 塞在getTask方法中的workQueue.take();即等待任务队列中有任务。 4. 任务缓存队列及排队策略 在前面我们多次提到了任务缓存队列,即workQueue,它用来存放等待执行的任务 。workQueue的类型为BlockingQueue,通常可以取下面三种类型: ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时

45、必须指定大 小; LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队 列大小,则默认为Integer.MAX_VALUE; synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。 5. 任务拒绝策略 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如 果还有任务到来就会采取任务拒绝策略,通常有以下四种策略: ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionExcep tion异常。 ThreadPool

46、Executor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后 重新尝试执行任务(重复此过程) ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 6. 线程池的关闭 ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和s hutdownNow(),其中: shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都 执行完后才终止,但再也不会接受新的任务 shutdown

47、Now():立即终止线程池,并尝试打断正在执行的任务,并且清空任 务缓存队列,返回尚未执行的任务 7. 线程池容量的动态调整 ThreadPoolExecutor提供了动态调整线程池容量大小的方法:setCorePoolSize() 和setMaximumPoolSize(), setCorePoolSize:设置核心池大小 setMaximumPoolSize:设置线程池最大能创建的线程数目大小 当上述参数从小变大时,ThreadPoolExecutor进行线程赋值,还可能立即创建新 的线程来执行任务。主要是ThreadPoolExecutor的实现原理 Java并发编程:线程池的使用1.3

48、.101.3.10线程池的几种方式线程池的几种方式newFixedThreadPool(int nThreads) 创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大 数量,这时线程规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个 新的线程newCachedThreadPool() 创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,而 当需求增加时,则可以自动添加新线程,线程池的规模不存在任何限制newSingleThreadExecutor() 这是一个单线程的Executor,它创建单个工作线程来执行任务,如果这个线程异常结束, 会创建一个新的来替代它;它的特点是能确保依照任务在队列中的顺序来串行执行newScheduledThreadPool(int corePoolSize) 创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。参考:创建线程池的几种方式1.3.111.3.11线程的生命周期线程的生命周期新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态 (1)

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 教案示例

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com