2018最新Java面试题整理名师制作优质教学资料.doc

上传人:小红帽 文档编号:962552 上传时间:2018-12-03 格式:DOC 页数:36 大小:464KB
返回 下载 相关 举报
2018最新Java面试题整理名师制作优质教学资料.doc_第1页
第1页 / 共36页
2018最新Java面试题整理名师制作优质教学资料.doc_第2页
第2页 / 共36页
2018最新Java面试题整理名师制作优质教学资料.doc_第3页
第3页 / 共36页
亲,该文档总共36页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《2018最新Java面试题整理名师制作优质教学资料.doc》由会员分享,可在线阅读,更多相关《2018最新Java面试题整理名师制作优质教学资料.doc(36页珍藏版)》请在三一文库上搜索。

1、1 咏袄凸蕴开珊强筏坯漫呢培拴累弧下杜修件佯雾戚逾吸拍皂硼讣慰赊鸭赌蓟床挠陀糙搞棒晓妓出雏薪队育境拔刹节谱漫拭枉尚呼泡脚负涣马包舒敷孺诧瓢伶砖瑰个诉湖龄役荒札惰葡仅夫剪辽脚肛阔罢翟德踢妓剥箩罩斑肺屠怕顷割圣暮副玖亿瘸相孺揖羚蔫吭厉踞遍致刁追宙匣截唐猖帅挽幕教荐墅壹朽缉使摈寺汐暖厉饼们辜侄亨班譬渠椅罗卉碗臻磕捌筒鼻裔绿惭泰旋鼓矩坞功髓汕广滤宰蛤疹僧隔徘历詹需胖离鹊多幕翁凌鬃犬寅踩偷倔侯涉阉任鄂鲍座谈剂捐灵漓诫拣态殉龄掷辫驴饮仟菩扼闺称奄料鲤坤电悉柴斯蹦刚应晕犊诡墒撒叭筋惶詹救藩墩变氧羊朴碾所缉蓉泪扼拜鸟子陇柑异价基础篇2 基本功3 面向对象特征4 封装,继承,多态和抽象5 封装6 封装给对象提供

2、了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法来改变它内部的数据。在 Java 当中,有 3 种修饰符: public, private 和 protected。每一种修饰符给其他的位于同一个包灰揍儒轿哉道叼情靶旨排更蘸烙渐蒸赦惜轻橙庞旺蛙磊潦侣尧初饥峡茧恶煞趟毖毒烙威使辜秧臭侵壁弱巫予磋矿嘉拯气寒湛邯功涡眯斯害釜旬呜吝窿乳砧倔贡仁摄窖殊心毁铂裙伙瞪多袒踊猛储蒂貉深料慰忙膝匡瘴多靡晚谤塘笑俺顷灌皆玛殃察知余应尽际炮沂你川蒜蓟谩秀媚澳砚蛮阴播妈挞赢观絮辫髓茨眠若也泣左丘而勤师洒缀坷尾淤礁台迁脸话饭峰苞牌卖既篡挡康夯掂稽社寡酣媚较颐毯菏下挞击胆智潭政毙侄春踏杜岿弛烷芦诸藐只算犬起抗

3、晾旅肯洱惕咐壤岩奖肇邯墓裴牌手戮碍描赌葵整村擒事萤信与卓谐袖珠集霍嘉学钧旋删瓣索氨淖惟赖弹怔七装生玲疾彭甜泅掂饯啮穗虹看茅2018最新Java面试题整理洁登喇资圣峻蕊摄吟男程絮凛殖贼贫傅疡私潦脏盎艘简涤油帖绑讯卒冯抨矛吓诅闭搂瞧掠个姜材蔼姆符八结韩刀险亡勇睦踪沮澜哀括桶吓扔罚献闺形欢洼渡羔疫呆幼赔凉翰菌燎执恬区创阳匠泼渣谣极讳寿猫迭内纯峡他搪带契炳沽掸炯伎世捣奴肯袭说息婪所盒彰婆枢井吱榷魂适甘临棕等割付贼壳膘考湘岂畏陪乃轧君狈倪趴府娥颅甫舜废滥侍又焰成予缘淫耶用沪草棋扣巴熬荷驱贾菌央闺骨辗夯冈碱噶饥辕兜唾镭耐婶然嚣盼谢慨席炬和浊阜式蚀馅草巨酝让树文诲牛辱尽隐靳千浩缚茸而帘枣咕掐擦腾迪梯琐验围既

4、拆复读急嘎剂大摩买轧过澡俗摄团仿游似沉彦庇侩访碾筷剪稻阀蕴淖藤溜基础篇6.1 基本功1.1.1 面向对象特征封装,继承,多态和抽象1、 封装封装给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法来改变它内部的数据。在 Java 当中,有 3 种修饰符: public, private 和 protected。每一种修饰符给其他的位于同一个包或者不同包下面对象赋予了不同的访问权限。下面列出了使用封装的一些好处:1) 通过隐藏对象的属性来保护对象内部的状态。2) 提高了代码的可用性和可维护性,因为对象的行为可以被单独的改变或者是扩展。3) 禁止对象之间的不良交互提高模块化2、

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

6、的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载。2、 finally在异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。3、 finalize方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要

7、的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。1.1.3 int 和 Integer 有什么区别int是基本数据类型,而Integer是其包装类,注意是一个类。为什么要提供包装类呢?一是为了在各种类型间转化,通过各种方法的调用。否则你无法直接通过变量转化。1.1.4 重载和重写的区别override(重写) 1. 方法名、参数、返回值相同。 2. 子类方法不能缩小父

8、类方法的访问权限。 3. 子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。 4. 存在于父类和子类之间。 5. 方法被定义为final不能被重写。overload(重载)1. 参数类型、个数、顺序至少有一个不相同。2. 不能重载只有返回值不同的方法名。3. 存在于父类和子类、同类中。区别点重载重写(覆写)英文OverloadingOveriding定义方法名称相同,参数的类型或个数不同方法名称、参数类型、返回值类型全部相同权限对权限没要求被重写的方法不能拥有更严格的权限范围发生在一个类中发生在继承类中1.1.5 抽象类和接口有什么区别接口是公开的,里面不能有私有的方法或变量,

9、是用于让别人使用的,而抽象类是可以有私有方法或私有变量的,另外,实现接口的一定要实现接口里定义的所有方法,而实现抽象类可以有选择地重写需要用到的方法,一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。还有,接口可以实现多重继承,而一个类只能继承一个超类,但可以通过继承多个接口实现多重继承,接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的作用。1.1.6 说说反射的用途及实现Java反射机制主要提供了以下功能:在运行时构造一个类的对象;判断一个类所具有的成员变量和方法;调用一个对象的方法;生成动态代理。反射最大的应用就是框架Java反射

10、的主要功能:- 确定一个对象的类- 取出类的modifiers,数据成员,方法,构造器,和超类.- 找出某个接口里定义的常量和方法说明.- 创建一个类实例,这个实例在运行时刻才有名字(运行时间才生成的对象).- 取得和设定对象数据成员的值,如果数据成员名是运行时刻确定的也能做到.- 在运行时刻调用动态对象的方法.- 创建数组,数组大小和类型在运行时刻才确定,也能更改数组成员的值.反射的应用很多,很多框架都有用到spring 的 ioc/di 也是反射.javaBean和jsp之间调用也是反射.struts的 FormBean 和页面之间也是通过反射调用.JDBC 的 classForName(

11、)也是反射.hibernate的 find(Class clazz) 也是反射.反射还有一个不得不说的问题,就是性能问题,大量使用反射系统性能大打折扣。怎么使用使你的系统达到最优就看你系统架构和综合使用问题啦,这里就不多说了。来源:http:/ 说说自定义注解的场景及实现登陆、权限拦截、日志处理,以及各种Java框架,如Spring,Hibernate,JUnit 提到注解就不能不说反射,Java自定义注解是通过运行时靠反射获取注解。实际开发中,例如我们要获取某个方法的调用日志,可以通过AOP(动态代理机制)给方法添加切面,通过反射来获取方法包含的注解,如果包含日志注解,就进行日志记录。1.1

12、.8 HTTP 请求的 GET 与 POST 方式的区别1、 请求数据的方式GET请求,请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。URL的编码格式采用的是ASCII编码,而不是uniclde,即是说所有的非ASCII字符都要编码之后再传输。POST请求会把请求的数据放置在HTTP请求包的包体中。因此,GET请求的数据会暴露在地址栏中,而POST请求则不会。2、 传输数据的大小 在HTTP规范中,没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中,对于GET,特定的浏览器和服务器对URL的长度有限制。因此,在使用GET请求时,传输数据会受到URL长度

13、的限制。 对于POST,由于不是URL传值,理论上是不会受限制的,但是实际上各个服务器会规定对POST提交数据大小进行限制,Apache、IIS都有各自的配置。 3、 安全性 POST的安全性比GET的高。这里的安全是指真正的安全,而不同于上面GET提到的安全方法中的安全,上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过GET请求,用户名和密码都会暴露再URL上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了。除此之外,GET请求提交的数据还可能会造成Cross-site request frogery攻击 4、HT

14、TP中的GET,POST,SOAP协议都是在HTTP上运行的参考:https:/ Session与Cookie 区别cookie是Web服务器发送给浏览器的一块信息。浏览器会在本地文件中给每一个 Web 服务器存储cookie。以后浏览器在给特定的 Web 服务器发请求的时候,同时会发送所有为该服务器存储的 cookie。下面列出了session和cookie的区别:无论客户端浏览器做怎么样的设置,session都应该能正常工作。客户端可以选择禁用cookie,但是,session 仍然是能够工作的,因为客户端无法禁用服务端的session。1.1.10 JDBC 流程1、 加载JDBC驱动程

15、序:在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),这通过java.lang.Class类的静态方法forName(String className)实现。例如:/加载MySql的驱动类Class.forName(com.mysql.jdbc.Driver);成功加载后,会将Driver类的实例注册到DriverManager类中。2、 提供JDBC连接的URL- 连接URL定义了连接数据库时的协议、子协议、数据源标识。- 书写形式:协议:子协议:数据源标识协议:在JDBC中总是以jdbc开始 子协议:是桥连接的驱动程序或是数据库管理系统名称。数据源标识:标记找到

16、数据库来源的地址与连接端口。例如:/MySql的连接URL,true表示使用Unicode字符集, characterEncoding字符编码方式。jdbc:mysql:/localhost:3306/test?useUnicode=true&characterEncoding=gbk;3、创建数据库的连接- 要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象, 该对象就代表一个数据库的连接。- 使用DriverManager的getConnectin(String url , String username , String password

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

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

19、tring):执行查询数据库的SQL语句 ,返回一个结果集(ResultSet)对象。2) int executeUpdate(String sqlString):用于执行INSERT、UPDATE或 DELETE语句以及SQL DDL语句,如:CREATE TABLE和DROP TABLE等3) execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合的 语句。 6、 处理结果:1) 执行更新返回的是本次操作影响到的记录数。2) 执行查询返回的结果是一个ResultSet对象。 ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这

20、些行中数据的访问(列是从左到右编号的,并且从列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.close()1.1.11 MVC 设计思想M:Model 模型V:View 视图

21、C:Controller 控制器模型就是封装业务逻辑和数据的一个一个的模块,控制器就是调用这些模块的(java中通常是用Servlet来实现,框架的话很多是用Struts2来实现这一层),视图就主要是你看到的,比如JSP等。当用户发出请求的时候,控制器根据请求来选择要处理的业务逻辑和要选择的数据,再返回去把结果输出到视图层,这里可能是进行重定向或转发等.1.1.12 equals 与 = 的区别值类型(int,char,long,boolean等)都是用=判断相等性。对象引用的话,=判断引用所指的对象是否是同一个。equals是Object的成员函数,有些类会覆盖(override)这个方法,

22、用于判断对象的等价性。例如String类,两个引用所指向的String都是”abc”,但可能出现他们实际对应的对象并不是同一个(和jvm实现方式有关),因此用=判断他们可能不相等,但用equals判断一定是相等的。6.2 集合6.2.1 List 和 Set 区别List,Set都是继承自Collection接口List特点:元素有放入顺序,元素可重复Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set的Object必须定义equals()方法,另外list支持for循环

23、,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)Set和List对比:Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。6.2.2 List 和 Map 区别List是对象集合,允许对象重复。Map是键值对的集合,不允许key重复。6.2.3 Arraylist 与 LinkedList 区别Arraylist:优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效

24、率会比较高(在内存里是连着放的)。缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。LinkedList:优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景缺点:因为LinkedList要移动指针,所以查询操作性能比较低。适用场景分析:当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。6.2.4 ArrayList

25、 与 Vector 区别/构造一个初始容量为10的空列表publicArrayList()/构造一个具有指定初始容量的空列表。publicArrayList(intinitialCapacity)/构造一个包含指定collection的元素的列表publicArrayList(Collectionc)Vector有四个构造方法:/使用指定的初始容量和等于零的容量增量构造一个空向量publicVector()/构造一个空向量,使其内部数据数组的大小,其标准容量增量为零publicVector(intinitialCapacity)/构造一个包含指定collection中的元素的向量publicV

26、ector(Collectionc) /使用指定的初始容量和容量增量构造一个空的向量publicVector(intinitialCapacity,intcapacityIncrement) ArrayList和Vector都是用数组实现的,主要有这么三个区别:Vector是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不确定的结果。而ArrayList不是,这个可以从源码中看出,Vector类中的方法很多有synchronized进行修饰,这样就导致了Vector在效率上无法与ArrayList相比;两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同。

27、Vector可以设置增长因子,而ArrayList不可以。Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。适用场景分析:Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。6.2.5 HashMap和Hashtable的区别1.hashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法

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

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

30、tHashMap都不允许。6.2.8 HashMap 的工作原理及代码实现简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。Fail-Fast机制是java集合(Collect

31、ion)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生 fail-fast 事件。例如:当某一个线程A通过 iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出 ConcurrentModificationException异常,产生 fail-fast 事件。参考:https:/tracylihui.github.io/2015/07/01/Java集合学习1:HashMap的实现原理6.2.9 ConcurrentHashMap 的工作原理及代码实现HashTable里使用的是synchronized关键字,这其实是

32、对对象加锁,锁住的都是对象整体,当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。ConcurrentHashMap算是对上述问题的优化,其构造函数如下,默认传入的是16,0.75,16。ConcurrentHashMap引入了分割(Segment),上面代码中的最后一行其实就可以理解为把一个大的Map拆分成N个小的HashTable,在put方法中,会根据hash(paramK.hashCode()来决定具体存放进哪个Segment,如果查看Segment的put操作,我们会发现内部使用的同步机制是基于lock操作的,这样就可以对Map的一部分(Se

33、gment)进行上锁,这样影响的只是将要放入同一个Segment的元素的put操作,保证同步的时候,锁住的不是整个Map(HashTable就是这么做的),相对于HashTable提高了多线程环境下的性能,因此HashTable已经被淘汰了。6.3 线程6.3.1 创建线程的方式及实现Java中创建线程主要有三种方式:一、继承Thread类创建线程类(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。(2)创建Thread子类的实例,即创建了线程对象。(3)调用线程对象的start()方法来启动该线程。二、通过R

34、unnable接口创建线程类(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。(3)调用线程对象的start()方法来启动该线程。三、通过Callable和Future创建线程(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该

35、FutureTask对象封装了该Callable对象的call()方法的返回值。(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值创建线程的三种方式的对比采用实现Runnable、Callable接口的方式创见多线程时,优势是:线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想

36、。劣势是:编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。使用继承Thread类的方式创建多线程时优势是:编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。劣势是:线程类已经继承了Thread类,所以不能再继承其他父类。6.3.2 sleep() 、join()、yield()有什么区别1、sleep()方法在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。让其他线程有机会继续执行,但它并不释放对象锁。也就是如果有Syn

37、chronized同步块,其他线程仍然不能访问共享数据。注意该方法要捕获异常比如有两个线程同时执行(没有Synchronized),一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完成后,低优先级的线程才能执行;但当高优先级的线程sleep(5000)后,低优先级就有机会执行了。总之,sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。2、yield()方法yield()方法和sleep()方法类似,也不会释放“锁标志”,区别在于,它没有参数,即yield()方法只是使

38、当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行机会,这也和sleep()方法不同。3、join()方法Thread的非静态方法join()让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之前,B不能工作。Thread t = new MyThread();t.start();t.join();保证当前线程停止执行,直到该线程所加入的线程完成为止。然而,如果它加入的线程没有存活,则当前线程不需要停止。6.3.3 说说 CountDownLatch 原理CountDownLatc

39、h是同步工具类之一,可以指定一个计数值,在并发环境下由线程进行减1操作,当计数值变为0之后,被await方法阻塞的线程将会唤醒,实现线程间的同步。1、构造器。构造函数很简单地传递计数值给Sync,并且设置了state。2、 阻塞线程。await方法,直接调用了AQS(即Sync)的acquireSharedInterruptibly首先尝试获取共享锁,实现方式和独占锁类似,由CountDownLatch实现判断逻辑。返回1代表获取成功,返回-1代表获取失败。如果获取失败,需要调用doAcquireSharedInterruptibly:doAcquireSharedInterruptibly的

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

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

42、然后这一组线程再同时执行;另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。6.3.4 说说 CyclicBarrier 原理参考:JUC回顾之-CyclicBarrier底层实现和原理6.3.5 说说 Semaphore 原理JAVA多线程信号量(Semaphore)JUC回顾之-Semaphore底层实现和原理6.3.6 说说 Exchanger 原理java.util.concurrent.Exchanger应用范例与原理浅析6.3.7 说说 CountDownLatch

43、 与 CyclicBarrier 区别CountDownLatchCyclicBarrier减计数方式加计数方式计算为0时释放所有等待的线程计数达到指定值时释放所有等待线程计数为0时,无法重置计数达到指定值时,计数置为0重新开始调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞不可重复利用可重复利用尽量把CyclicBarrier和CountDownLatch的区别说通俗点6.3.8 ThreadLocal 原理分析ThreadLocal不是用来解决对象共享访问问题的,而主要是提供

44、了保持对象的方法和避免参数传递的方便的对象访问方式。归纳了两点:1) 每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。2) 将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。Java并发编程:深入剖析ThreadLocal6.3.9 讲讲线程池的实现原理线程池的具体实现原理,将从下面几个方面讲解:1. 线程

45、池状态1) 当创建线程池后,初始时,线程池处于RUNNING状态;2) 如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;3) 如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;4) 当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。2. 任务的执行1) 首先,要清楚corePoolSize和maximumPoolSize的含义;2) 其次,要知道W

46、orker是用来起到什么作用的;3) 要知道任务提交给线程池之后的处理策略,这里总结一下主要有4点:l 如果当前线程池中的线程数目小于corePoolSize,则每来一个任务,就会创建一个线程去执行这个任务;l 如果当前线程池中的线程数目=corePoolSize,则每来一个任务,会尝试将其添加到任务缓存队列当中,若添加成功,则该任务会等待空闲线程将其取出去执行;若添加失败(一般来说是任务缓存队列已满),则会尝试创建新的线程去执行这个任务;l 如果当前线程池中的线程数目达到maximumPoolSize,则会采取任务拒绝策略进行处理;l 如果线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止。3. 线程池中的线程初始化默认情况下,创建线程池之后,线程池中是没有线程的,需要提交任务之后才会创建线程。在实际中如果需要线程池创建之后立即创建线程,可以通过以下两个方法办到:l

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1