2018最新Java面试题整理_第1页
2018最新Java面试题整理_第2页
2018最新Java面试题整理_第3页
免费预览已结束,剩余31页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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

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

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

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

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

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

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

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

9、过反射来获取方法包含的注解,如果包含日志注解,就进展日志记录。1.1.8 请求的 GET 与 POST 方式的区别1、请求数据的方式GET请求,请求的数据会附加在 URL之后,以?分割URL和传输数据,多个参数用&连接。 URL的编码格式采用的是 ASCII编码,而不是 uniclde,即是说所有的非 ASCII字符都 要编码之后再传输。POST请求会把请求的数据放置在请求包的包体中。因此,GET请求的数据会暴露在地址栏中,而POST青求那么不会。2、传输数据的大小在标准中,没有对URL的长度和传输的数据大小进展限制。但是在实际开发过程中,对于GET特定的浏览器和效劳器对 URL的长度

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

11、ss-site request frogery 攻击4、中的GET POST SOAF协议都是在上运行的1.1.9 Session 与 Cookie 区别cookie是Web效劳器发送给浏览器的一块信息。浏览器会在本地文件中给每一个 Web效劳器 存储 cookie 。以后浏览器在给特定的 Web 效劳器发请求的时候,同时会发送所有为 该效劳器存储的 cookie 。下面列出了 session 和 cookie 的区别: 无论客户端浏览器做怎么样的设置, session 都应该能正常工作。 客户端可以选择禁用 cookie ,但是, session 仍然是能够工作的,因为客户端无法禁 用效劳端

12、的 session 。1.1.10 JDBC 流程1、加载JDBC驱动程序:在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM Java 虚拟机,这通过 java.lang.Class 类的静态方法 forName(String className) 实现。例如:/ 加载 MySql 的驱动类 Class.forName("com.mysql.jdbc.Driver"); 成功加载后,会将 Driver 类的实例注册到 DriverManager 类中。2、提供JDBC连接的URL-连接URL定义了连接数据库时的协议、子协议、数据源标识。- 书写形式:协议:子协议:

13、数据源标识协议:在JDBC中总是以jdbc开场子协议:是桥连接的驱动程序或是数据库管理系统名称。 数据源标识:标记找到数据库来源的地址与连接端口。例如:/MySql 的连接 URL, true 表示使用 Unicode 字符集 , characterEncoding 字符编码方式。 jdbc:mysql:/localhost:3306/test?useUnicode=true&characterEncoding=gbk;3、创立数据库的连接- 要连接数据库,需要向 java.sql.DriverManager 请求并获得 Connection 对象, 该对象 就代表一个数据库的连接。-

14、 使用 DriverManager 的 getConnectin(String url , String username , String password )方法传入指定的欲连接的数据库的路径、数据库的用户名和密码来获得。例如:/ 连接 MySql 数据库,用户名和密码都是 root String url = "jdbc:mysql:/localhost:3306/test"Connection con = DriverManager.getConnection(url, "root","root")4、 创立一个 Stateme

15、nt,要执行 SQL语句,必须获得 java.sql.Statement实例,Statement 实例分为以下 3 种类型:1) 执行静态SQL语句。通常通过 Statement实例实现。Statement stmt = con.createStatement() ;2) 执行动态SQL语句。通常通过 PreparedStatement 实例实现。 PreparedStatement pstmt = con.prepareStatement(sql) ;3) 执行数据库存储过程。通常通过 CallableStatement 实例实现。CallableStatement cstmt = con.

16、prepareCall(“CALL demoSp(? , ?) ) ;5、执行SQL语句提供了三种执行 SQL语句的方法:executeQuery 、executeUpdate 和 execute1) ResultSet executeQuery(String sqlString):执行查询数据库的 SQL 语句 ,返回一个结果集 ResultSet 对象。2) int executeUpdate(String sqlString):用于执行 INSERT UPDATE或 DELETE 语句以及 SQL DDL语句,如:CREATE TABLED DROP TABLE?6、7、3) execu

17、te(sqlString): 用于执行返回多个结果集、多个更新计数或二者组合的 句。处理结果:1) 执行更新返回的是本次操作影响到的记录数。2) 执行查询返回的结果是一个 ResultSet 对象。? ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些行中数据的访问列是从左到右编号的,并且从列1 开场。? 使用结果集 ResultSet 对象的访问方法获取数据: while(rs.next()String name = rs.getString( String pass = rs.getString(1) ; /关闭JDBC对象操作完成以后要把所有使用的J

18、DBC寸象全都关闭,以释放 JDBC资源,关闭顺序和声明顺序相反:1) 关闭记录集 rs.close()2) 关闭声明 stmt.close()name ) ;此方法比拟高效MVC设计思想3) 关闭连接寸象 conn.close()M:Model 模型 V:View 视图, 比方 JSP 等。, 控制器根据请求来选择要处理的业务逻辑和要选择的数据, 这里可能是进展重定向或转发等 ., 再返回C:Controller 控制器 模型就是封装业务逻辑和数据的一个一个的模块 , 控制器就是调用这些模块的 (java 中通常是用 Servlet 来实现 , 框架的话很多是用 Struts2 来实现这一层

19、 ), 视图就主要是你看到的 当用户发出请求的时候 去把结果输出到视图层1.1.12 equals 与 = 的区别值类型 int,char,long,boolean 等都是 用 =判断相等性 。寸象引用的话,=判断引用所指的寸象是否是同一个。equals 是 Object 的成员函数,有些类会覆盖 override 这个方法,用于判断寸象的 等价性。例如String类,两个引用所指向的Stri ng都是"abc",但可能出现他们实际对应的寸象并不是同一个和 jvm 实现方式有关 ,因此用 =判断他们可能不相等,但用equals判断一定是相等的。1.2 集合1.2.1 Lis

20、t 和 Set 区别List,Set 都是继承自 Collection 接口List 特点: 元素有放入顺序,元素可重复Set 特点: 元素无放入顺序,元素不可重复 ,重复元素会覆盖掉注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,参加 Set 的 Object 必须定义 equals() 方法,另外 list 支持 for 循 环,也就是通过下标来遍历,也可以用迭代器,但是 set 只能用迭代,因为他无序,无法用 下标来取得想要的值。 Set 和 List 比照:Set : 检索元素效率低下,删除和插入效率高 ,插入和删除不会引起元素

21、位置改变。List :和数组类似, List 可以动态增长,查找元素效率高,插入删除元素效率低 ,因为会 引起其他元素位置改变。1.2.2 List 和 Map 区别List 是 对象集合,允许对象重复 。Map是键值对的集合,不允许key重复。1.2.3 Arraylist 与 LinkedList 区别Arraylist :优点: ArrayList 是实现了 基于动态数组的数据构造 ,因为地址连续 ,一旦数据存储好了, 查询操作效率会比拟高在内存里是连着放的 。缺点:因为地址连续, ArrayList 要移动数据 , 所以插入和删除操作效率比拟低。LinkedList :优点: Link

22、edList 基于链表的数据构造 , 地址是任意的 ,所以在开辟内存空间的时候不需要 等一个连续的地址, 对于新增和删除操作 add 和 remove , LinedList 比拟占优势。 LinkedList 适用于要头尾操作或插入指定位置的场景 缺点:因为 LinkedList 要移动指针 , 所以查询操作性能比拟低。适用场景分析:当需要对数据进展对此访问的情况下选用 ArrayList ,当需要对数据进展屡次增加删除修改 时采用 LinkedList 。1.2.4 ArrayList 与 Vector 区别/ 构造一个 初始容量为 10 的空列表public ArrayList()/ 构

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

24、on<? extends E> c)/ 使用指定的初始容量和容量增量构造一个空的向量capacityIncrement)public Vector(int initialCapacity,intArrayList 和 Vector 都是用数组实现的,主要有这么三个区别:Vector 是多线程平安的 ,线程平安就是说多线程访问同一代码,不会产生不确定的结果。而 ArrayList 不是,这个可以从源码中看出, Vector 类中的方法很多有 synchronized 进展 修饰,这样就导致了 Vector 在效率上无法与 ArrayList 相比 ; 两个都是采用的线性连续空间存储元

25、素, 但是当空间缺乏的时候, 两个类的增加方式是不同。 Vector 可以设置增长因子,而 ArrayList 不可以。Vector 是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。适用场景分析:Vector 是线程同步的,所以它也是线程平安的,而 ArrayList 是线程异步的,是不平安的 。 如果不考虑到线程的平安因素,一般用 ArrayList 效率比拟高。如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比拟大的数据, 用 Vector 有一定的优势。125 HashMap和 Hashtable 的区别1. hashMap 去掉了 HashTable 的

26、contains 方法,但是加上了 containsValue 和 containsKey 方法。2. hashTable同步的,而 HashMap是非同步的,效率上逼 hashTable要高。3. hashMap 允许空键值,而 hashTable 不允许 。TreeMap:非线程平安基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。Treemap:适用于按自然顺序或自定义顺序遍历键(key)。1.2.6 HashSet 和 HashMap 区别set 是 线性构造 , set 中的 值不能重复 , hashset 是 set 的 hash 实现, hashset 中值不

27、能重复是用hashmap的key来实现的。map是键值对映射,可以空键空值 。HashMap是Map接口的hash实现,key的唯一性是 通过 key 值 hash 值的唯一来确定, value 值是那么是链表构造。他们的共同点都是 hash 算法实现的唯一性,他们都不能持有根本类型,只能持有对象1.2.7 HashMap和 ConcurrentHashMap 的区别ConcurrentHashMap是线程平安的 HashMap的实现。1ConcurrentHashMap 对整个桶数组进展了分割分段 (Segment) ,然后在每一个分段上都用 lock 锁进展保护,相对于 HashTable

28、 的 syn 关键字锁的粒度更精细了一些,并发性能更 好,而HashMap没有锁机制,不是线程平安的。2HashMap的键值对允许有 null,但是 ConCurrentHashMap都不允许。1.2.8 HashMap的工作原理及代码实现简单地说, HashMap 在底层将 key-value 当成一个整体进展处理,这个整体就是一个Entry 对象。 HashMap 底层采用一个 Entry 数组来保存所有的 key-value 对,当需要存 储一个 Entry 对象时,会根据 hash 算法来决定其在数组中的存储位置,在根据 equals 方法决定其在该数组位置上的链表中的存储位置;当需要

29、取出一个 Entry时,也会根据 hash算法找到其在数组中的存储位置,再根据 equals方法从该位置上的链表中取出该Entry。Fail-Fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进展操作时,就可能会产生fail-fast 事件。例如:当某一个线程 A通过iterator去遍历某集合的过程中,假设该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出Co ncurre ntModificati on Exception异常,产生fail-fast 事件。参考:ihui.github.io/2021 /07/01/Java集合学

30、习 1: HashMap的实现原理1.2.9 CorcurrentHashMap的工作原理及代码实现HashTable里使用的是synchronized 关键字,这其实是对对象加锁,锁住的都是对象 整体,当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。ConcurrentHashMap算是对上述问题的优化,其构造函数如下,默认传入的是16,0.75,16。public(int initialCapacity,float loadFdctor, xnt uncurrencyLevelif (ioadFactor > 0) 'I initi

31、al匚总匸y < 0 11 concurtencyLevel Q) throw newlArgvinntExcept ion ();if (concurrcyLeve 1 >巩时concurrencyLevel -/ Find power- of two sizes best matarguitantint 33hi= 0;int ss:se = 1;while ai ze < c on cm rrs n cyLs ve1) + 1 ashiftjssize «= 1;thia,segmentShi ft - 32 - sshi ft;this»aegme

32、ntMask = ssize - 1;if (initialCapacity > MAXIMVMCAPACITY) InitialCapaeity = MAXIM喊CAPACITYint c = initialCapacity / S3iz&it (c * ssize < initialcapacity)+c;int cap -TAELE CAPAC I TYfwhile (cp < c)cap «= 1;/ create sgment and aegmnta0JSeginent<Kj V> &0 -n«w Segr.erLt&

33、lt;Kj V>(loadFaatoi:/ (int) (cap * loadfactor), (HashEntry<Kj V>)new HashEntry(cap;Seqment<K; V> ' ss = (Sf?qnient<K, V> ) new Seqirent' ss i ; tSdwrmdObjECt (弟,5£A5£, sO) ;7c:'jre': wriT gl 开苏乍二this segments - nn;public V | K keyr V value) Segment<K

34、r V> s;if (value = null七hrow new Nul lPr>j nterExcept i r »ri ();int hash = hash(key)tint j (hash. >» segment-Shift 4 segmentMsk;if ( s = (Segment<KrV>)qetOb ject/ nonvolatile; recheck(segment?,(j « SSHIFT + SBASE) ) = null) / / In ft ph r-Sqni-nta = ensureSegment(j);re

35、turn s.put(key hashf value, false)rConcurrentHashMap弓I入了分割(Segment),上面代码中的最后一行其实就可以理解为 把一个大的 Map拆分成N个小的HashTable ,在put方法中,会根据hash(paramK.hashCode() 来决定具体存放进哪个Segment,如果查看Segment的put操作,我们会发现内部使用的同步机制是基于lock操作的,这样就可以对Map的一局部Segment进展上锁,这样影响的只是将要放入同一个Segment的元素的put操作,保证同步的时候,锁住的不是整个MapHashTable就是这么做的,相

36、对于HashTable提高了多线程环境下的性能,因此HashTable已经被淘汰了。1.3线程创立线程的方式及实现Java中创立线程主要有三种方式:一、继承Thread类创立线程类1定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要 完成的任务。因此把 run()方法称为执行体。2创立Thread子类的实例,即创立了线程对象。3调用线程对象的start()方法来启动该线程。二、通过Runnable接口创立线程类1定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。2创立Runnable实现类的实例,

37、并依此实例作为 Thread的target来创立Thread对象, 该Thread对象才是真正的线程对象。3调用线程对象的start()方法来启动该线程。三、通过 Callable 和Future创立线程1创立Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体, 并且有返回值。2创立Callable 实现类的实例,使用FutureTask类来包装 Callable 对象,该FutureTask 对象封装了该Callable对象的call()方法的返回值。3使用FutureTask对象作为Thread对象的target创立并启动新线程。4调用FutureTa

38、sk对象的get()方法来获得子线程执行完毕后的返回值public class CalLabieThradTest Impleients Callable<Integer> public static void main (String argg) throws InterruptedxceptlotirExecutionException CallableThreadTest ctt = naw CallableThreadTeat); FutureTask<_ntegsr> ft - new tut-ireTa3k:<Integer> (ctt); Th

39、read t = new Thread (ft, FutnreTask'*); 匕.start ();System.out»printin(nF口导k*+ ft.get();public Integer call() throws Exception int i=0;for (; i < 5/ i+*) System* out * printin (Thread* currentThreacf ( *getName ) + ,T ,r + i); return i;创立线程的三种方式的比照采用实现Runnable、Callable 接口的方式创见多线程时,优势是: 线程

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

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

42、级就有时机执行了。总之,sleep()可以使低优先级的线程得到执行的时机,当然也可以让同优先级、高优先级 的线程有执行的时机。2、yield()方法yield()方法和sleep()方法类似,也不会释放"锁标志",区别在于,它没有参数,即yield()方法只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行时机,这也和 sleep()方法不同。3、join()方法Thread的非静态方法join()让一个线程B “参加"到另外一个线程A的尾部。在A执行完

43、毕之前,B不能工作。Thread t = new MyThread();t.start();t.joi n();保证当前线程停顿执行,直到该线程所参加的线程完成为止。然而,如果它参加的线程没有 存活,那么当前线程不需要停顿。1.3.3 说说 CountDownLatch 原理CountDownLatch是同步工具类之一,可以指定一个计数值,在并发环境下由线程进展减1操作,当计数值变为 0之后,被await方法阻塞的线程将会唤醒,实现线程间的同步。1、构造器。构造函数很简单地传递计数值给Sync,并且设置了 state 。* Constructs a code 匚ountDownLatch in

44、itialized with the given count»A* param uoun二 the ni-imber oflink frcountQc?vjnJ must be invoked* before threads can pass through await* throws 11 legalArgumentException if fcount ia netjat ive(int count)if |count < 0) throw new IllegalArgumentExceptioncount < this= new Synccoiint);2、阻塞线程

45、。await 方法,直接调用了 AQS即卩 Sync )的 acquireSharedlnterruptibly public void FBSfCI <) throws InterruptedtKcept ion ( sync. acquireSharedln(I);throws InterruptedException if (Thread.)threw new Interru.ptedExcept丄 if (txyAcquireShared(arg) < 0)ctoAcquirr Shared I w tEiriruFtibLy (门匸 g);首先尝试获取共享锁,实现方式和独

46、占锁类似,由CountDownLatch实现判断逻辑。返回1代表获取成功,返回-1代表获取失败。如果获取失败,需要调用doAcquireSharedI nterruptiblyAcquires in sha匚md interrujjtible mode Rparam arg "the ac<jui_e argumen'tprivate void|(int arg)throws Intt!rruptdExcptiun final Node node = addWAiter(Node.SHARED)? boolean failed = true;try Ifor (;) f

47、inal Node p - node,predecessor(); if (p = headJ int r = tryAcqiiirShard (augi ; if (r >= 0) aetHcadTkridPropaqat (nodet r)丿p>next = null; /; hlp GC failed - false;芒e七uirn;if (shouldParkAfterFailedAquire(p7 node) &在 parkAndCheckInterrupt()throw new I ritprruptsdKxGept; i <»fl ();)fi

48、nally fif (failedcancelAcquire i:node);1doAcquireSharedl nterruptibly的逻辑和独占功能具体如下:1) 创立的Node是定义成共享的Node.SHARED;2) 被唤醒后重新尝试获取锁,不只设置自己为head,还需要通知其他等待的线程。重点看后文释放操作里的setHeadAndPropagate3、释放操作。countDown操作实际就是释放锁的操作,每调用一次,计数值减少1。* Decrements the count of the latch, releasing all vaiting threads if 1 the c

49、ount reaches zero *<p>lf iLhe current, count, is greater than zero then it 丄芒 decremented, if the new count in zero then sll waiting threads are re-enabled for thread scheduling purposes<p>If the current connt equals zero then nothing happens.public void cQunDown)sync,releaseShared(1|;*

50、Releases in shared mode Implemented by unblocking one or mere1 threads if link tryReleaaeShared returns true.* param arg the release 日uguinuirt * This value is conveyed to+(01 ink iryRp 1 eaShared b*;t i f? ottiprwii" iwi ntrrprptpri* and can represent anything you 11ke»* 上日turn the value

51、二总turned from glink ItryReleaseShared*/public final boolean rpeaseShared(int arg) if JtryReleaseShared(arg doRelea呂启占harEti (丨return true;return false;1同样是首先尝试释放锁,具体实现在CountDownLatch中:死循环加上cas的方式保证state的减1操作,当计数值等于 0,代表所有子线程都执行完 毕,被await阻塞的线程可以唤醒了,下一步调用doReleaseShared :aignal successor and ensure* R

52、elease action fur shcirecL moae* propagation (Note: For exclusive Tnoder release just amounts* to calling unparkSuccessor of head if it needs sig口ml*)private void()* Ensure that a releaseeven if there are other* in-progress aaquires/release. This proceeds in the 口鬥口耳丄* way of trying to unparkSuocess

53、or of head if it needs* signalv But if it does notf status is 再ct tc PROPAGATE to* ensure that upon rele=sef propagation continues.* Add!t i i inal ly, we must 1 oop in casp anode i.s added* while we are doing th is - Al soj unlike other uses of* unparkSuccessor, we need to know if CAS to reset stat

54、us* fails, if sa rechecking,ford INode h = head;if (h !- null && h !- tail) int wl5 = h.WdiLSLdtu.ii:if (w吕=Node EIGNW if !Node *0)continue;/ loop torecheck eases1unparkSuccessor(h);JFelse if |ws0 机*!aampatWai(h, 0,Node. PROPAGATE)1con 七 imi 目:/ loop onfailed CASJ if (h=/ loop ifhead changed

55、break;标记1里,头节点状态如果 SIGNAL,那么状态重置为 0,并调用unparkSuccessor唤醒下个 节点。标记2里,被唤醒的节点状态会重置成0,在下一次循环中被设置成PROPAGAT状态,代表状态要向后传播。分析CountDownLatch的实现原理什么时候使用 Cou ntDow nLatchJava 并发编程: CountDownLatch、CyclicBarrier禾口 Semaphore1) CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:CountDownLatch 般用于某个线程 A等待假设干个其他线程执行完

56、任务之后,它才执 行;而CyclicBarrier 一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行; 另外,CountDownLatch是不能够重用的,而 CyclicBarrier是可以重用的。2Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。1.3.4 说说 CyclicBarrier 原理JUC回忆之-CyclicBarrier底层实现和原理135 说说Semaphore原理JAVA多线程-信号量(Semaphore)JUC回忆之-Semaphore底层实现和原理136说说Exchanger原理java.util.c on curre nt.Excha nger应用范例与原理浅析137 说说 CountDownLatch 与 CyclicBarrier 区别Coun tDow nLatchCyclicBarrier减计数方式加计数方式计算为0时释放所有等待的线程计数到达指定值时释放所有等待线程计数为0时,无法重置计数到达指定值时,计数置为0重新开场调用cou ntDow n()方法计数减一,调用调用

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论