Java高级面试题及答案

编程之家收集整理的这篇文章主要介绍了Java高级面试题及答案编程之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

List和Set比较,各自的子类比较

对比一:Arraylist与LinkedList的比较

1、ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。

2、因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。

3、LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。

4、因为LinkedList要移动指针,所以查询操作性能比较低。

适用场景分析:

当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。

对比二:ArrayList与Vector的比较

1、Vector的方法都是同步的,是线程安全的,而ArrayList的方法不是,由于线程的同步必然要影响性能。因此,ArrayList的性能比Vector好。 

2、当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样。ArrayList就有利于节约内存空间。

3、大多数情况不使用Vector,因为性能不好,但是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性。

4、Vector可以设置增长因子,而ArrayList不可以。

适用场景分析:

1、Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。

2、如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。

对比三:HashSet与TreeSet的比较

1.TreeSet 是二叉树实现的,Treeset中的数据是自动排好序的,不允许放入null值 。

2.HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束 。

3.HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例。

适用场景分析:

HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。

HashMap和ConcurrentHashMap的区别

1、HashMap不是线程安全的,而ConcurrentHashMap是线程安全的。

2、ConcurrentHashMap采用锁分段技术,将整个Hash桶进行了分段segment,也就是将这个大的数组分成了几个小的片段segment,而且每个小的片段segment上面都有锁存在,那么在插入元素的时候就需要先找到应该插入到哪一个片段segment,然后再在这个片段上面进行插入,而且这里还需要获取segment锁。

3、ConcurrentHashMap让锁的粒度更精细一些,并发性能更好。

JVM的内存结构

根据 JVM 规范,JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。

1、Java虚拟机栈:

线程私有;每个方法在执行的时候会创建一个栈帧,存储了局部变量表,操作数栈,动态连接,方法返回地址等;每个方法调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。

2、堆:

线程共享;被所有线程共享的一块内存区域,在虚拟机启动时创建,用于存放对象实例。

3、方法区:

线程共享;被所有线程共享的一块内存区域;用于存储已被虚拟机加载的类信息,常量,静态变量等。

4、程序计数器:

线程私有;是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为“线程私有”的内存。

5、本地方法栈:

线程私有;主要为虚拟机使用到的Native方法服务。

强引用,软引用和弱引用的区别

强引用:

只有这个引用被释放之后,对象才会被释放掉,只要引用存在,垃圾回收器永远不会回收,这是最常见的New出来的对象。

软引用:

内存溢出之前通过代码回收的引用。软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。

弱引用:

第二次垃圾回收时回收的引用,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记

springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的

核心:

控制反转和面向切面

请求处理流程:

1、首先用户发送请求到前端控制器,前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分;

2、页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,并进行验证,然后将命令对象委托给业务对象进行处理;处理完毕后返回一个ModelAndView(模型数据和逻辑视图名);

3、前端控制器收回控制权,然后根据返回的逻辑视图名,选择相应的视图进行渲染,并把模型数据传入以便视图渲染;

4、前端控制器再次收回控制权,将响应返回给用户

控制反转如何实现:

我们每次使用spring框架都要配置xml文件,这个xml配置了bean的id和class。

spring中默认的bean为单实例模式,通过bean的class引用反射机制可以创建这个实例。

因此,spring框架通过反射替我们创建好了实例并且替我们维护他们。

A需要引用B类,spring框架就会通过xml把B实例的引用传给了A的成员变量。

BIO、NIO和AIO的区别

Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。

Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

Java AIO: 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。

NIO比BIO的改善之处是把一些无效的连接挡在了启动线程之前,减少了这部分资源的浪费(因为我们都知道每创建一个线程,就要为这个线程分配一定的内存空间)

AIO比NIO的进一步改善之处是将一些暂时可能无效的请求挡在了启动线程之前,比如在NIO的处理方式中,当一个请求来的话,开启线程进行处理,但这个请求所需要的资源还没有就绪,此时必须等待后端的应用资源,这时线程就被阻塞了。

适用场景分析:

BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解,如之前在Apache中使用。

NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持,如在 Nginx,Netty中使用。

AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持,在成长中,Netty曾经使用过,后来放弃。

为什么要用线程池

那先要明白什么是线程池

线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。

使用线程池的好处

1、线程池改进了一个应用程序的响应时间。由于线程池中的线程已经准备好且等待被分配任务,应用程序可以直接拿来使用而不用新建一个线程。

2、线程池节省了CLR 为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。

3、线程池根据当前在系统中运行的进程来优化线程时间片。

4、线程池允许我们开启多个任务而不用为每个线程设置属性

5、线程池允许我们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。

6、线程池可以用来解决处理一个特定请求最大线程数量限制问题。

悲观锁和乐观锁的区别,怎么实现

悲观锁:一段执行逻辑加上悲观锁,不同线程同时执行时,只能有一个线程执行,其他的线程在入口处等待,直到锁被释放。

乐观锁:一段执行逻辑加上乐观锁,可以同时进入执行,在最后更新数据的时候要检查这些数据是否被其他线程修改了(版本和执行初是否相同),没有修改则进行更新,否则放弃本次操作。

悲观锁的实现:

begin;/begin work;/
start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品
status为2update t_goods set status=2;
//4.提交事务
commit;/commit work;

乐观锁的实现:

1.查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根据商品信息生成订单
3.修改商品status为2
update t_goods 
set status=2,version=version+1
where id=#{id} and version=#{version};

什么是线程死锁?死锁如何产生?如何避免线程死锁?

死锁的介绍:

线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便占有了资源,直到它退出代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。

死锁的产生的一些特定条件:

1、互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放 。

2、请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。

3、不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用。

4、循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。

如何避免:

1、加锁顺序:

当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。如果能确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生。当然这种方式需要你事先知道所有可能会用到的锁,然而总有些时候是无法预知的。

2、加锁时限:

加上一个超时时间,若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。但是如果有非常多的线程同一时间去竞争同一批资源,就算有超时和回退机制,还是可能会导致这些线程重复地尝试但却始终得不到锁。

3、死锁检测:

死锁检测即每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。死锁检测是一个更好的死锁预防机制,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。

 

总结

以上是编程之家为你收集整理的Java高级面试题及答案全部内容,希望文章能够帮你解决Java高级面试题及答案所遇到的程序开发问题。

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您喜欢寻找一群志同道合、互帮互助的学习伙伴,可以点击下方链接加入:
编程之家官方1群:1065694478(已满)
编程之家官方2群:163560250(已满)
编程之家官方3群:312128206(已满)
编程之家官方4群:230427597

相关文章

猜你在找的Java面试题相关文章

聊聊SpringBoot和传统的SSM的区别? SpringBoot是Spring的扩展,在Spring的基础上,简化了传统的SSM开发繁琐的配置; 在部署上,SpringBoot内置了Tomcat,
在面试当中,有时候会问到你在项目中用过多线程么? 对于普通的应届生或者工作时间不长的初级开发 ???—— crud仔流下了没有技术的眼泪。 博主这里整理了项目中用到了多线程的一个简单的实例,希望能对你
前言 本文分为20多个问题,通过问题的方式,来逐渐理解jvm,由浅及深。希望帮助到大家。 1. Java类实例化时,JVM执行顺序? 正确的顺序如下: 1父类静态代码块 2父类静态变量 3子
1. Java线程的创建方式 (1)继承thread类 thread类本质是实现了runnable接口的一个实例,代表线程的一个实例。启动线程的方式start方法。start是一个本地方法,
1. List List 是有序的 Collection。Java List 一共三个实现类: 分别是 ArrayList、Vector 和 LinkedList ArrayList Arr
一、Spring面试题1、Spring 在ssm中起什么作用?Spring:轻量级框架作用:Bean工厂,用来管理Bean的生命周期和框架集成。两大核心:①. IOC/DI(控制反转/依赖注入) :把dao依赖注入到service层,service层反转给action层,Spring顶层容器为BeanFactory。②. AOP:面向切面编程2、Spring的事务?编程式事务管理:编程方式管理事务,极大灵活性,难维护。声明式事务管理:可以将业务代码和事务管理分离,用注解和xml配置来管理事务。3、IOC 在项目中的作用?作用:Ioc解决对象之间的依赖问题,把所有Bean的依赖关系通过配置文件或注解关联起来,降低了耦合度。4、Spring的配置文件中的内容?开启事务注解驱动事务管理器开启注解功能,并配置扫描包配置数据库配置SQL会话工厂,别名,映射文件不用编写Dao层的实现类5、Spring下的注解?注册:@Controller @Service @Component注入:@Autowired @Resource请求地址:@RequestMapping返回具体数据类型而非跳转:@ResponseBody6、Spring DI 的三种方式?构造器注入:通过构造方法初始化<constructor-arg index="0" type="java.lang.String" value="宝马"></constructor-arg>setter方法注入:通过setter方法初始化<property name="id" value="1111"></property>接口注入7、Spring主要使用了什么模式?工厂模式:每个Bean的创建通过方法单例模式:默认的每个Bean的作用域都是单例代理模式:关于Aop的实现通过代理模式8、IOC,AOP的实现原理?IOC:通过反射机制生成对象注入AOP:动态代理二、SpringMvc面试题1、SpringMvc 的控制器是不是单例模式,如果是,有什么问题,怎么解决?问题:单例模式,在多线程访问时有线程安全问题解决方法:不要用同步,在控制器里面不能写字段2、SpringMvc 中控制器的注解?@Controller:该注解表明该类扮演控制器的角色3、@RequestMapping 注解用在类上的作用?作用:用来映射一个URL到一个类或者一个特定的处理方法上4、前台多个参数,这些参数都是一个对象,快速得到对象?方法:直接在方法中声明这个对象,SpringMvc就自动把属性赋值到这个对象里面5、SpringMvc中函数的返回值?String,ModelAndView,List,Set 等一般String,Ajax请求,返回一个List集合6、SpringMvc中的转发和重定向?转发: return:“hello”重定向 :return:“redirect:hello.jsp”7、SpringMvc和Ajax之间的相互调用?通过JackSon框架把java里面对象直接转换成js可识别的json对象,具体步骤如下:加入JackSon.jar在配置文件中配置json的映射在接受Ajax方法里面直接返回Object,list等,方法前面需要加上注解@ResponseBody8、SpringMvc的工作流程图? 9、Struts2 和 SpringMvc的区别?入口不同:Struts2:filter过滤器SpringMvc:一个Servlet即前端控制器开发方式不同:Struts2:基于类开发,传递参数通过类的属性,只能设置为多例SpringMvc:基于方法开发(一个url对应一个方法),请求参数传递到方法形参,可以为单例也可以为多例(建议单例)请求方式不同:Struts2:值栈村塾请求和响应的数据,通过OGNL存取数据SpringMvc:通过参数解析器将request请求内容解析,给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过request域传输到页面,jsp视图解析器默认使用的是jstl。三、Mybatis面试题1、Ibatis和Mybatis?Ibatis:2010年,apache的Ibatis框架停止更新,并移交给了google团队,同时更名为MyBatis。从2010年后Ibatis在没更新过,彻底变成了一个孤儿框架。一个没人维护的框架注定被mybatis拍在沙滩上。Mybatis:Ibatis的升级版本。2、什么是Mybatis的接口绑定,有什么好处?Mybatis实现了DAO接口与xml映射文件的绑定,自动为我们生成接口的具体实现,使用起来变得更加省事和方便。3、什么情况用注解,什么情况用xml绑定?注解使用情况:Sql语句简单时xml绑定使用情况:xml绑定 (@RequestMap用来绑定xml文件)4、Mybatis在核心处理类叫什么?SqlSession5、查询表名和返回实体Bean对象不一致,如何处理?映射键值对即可<result column="title" property="title" javaType="java.lang.String"/>column:数据库中表的列名property:实体Bean中的属性名6、Mybatis的好处?把Sql语句从Java中独立出来。封装了底层的JDBC,API的调用,并且能够将结果集自动转换成JavaBean对象,简化了Java数据库编程的重复工作。自己编写Sql语句,更加的灵活。入参无需用对象封装(或者map封装),使用@Param注解7、Mybatis配置一对多?<collection property="topicComment" column="id" ofType="com.tmf.bbs.pojo.Comment" select="selectComment" />property:属性名column:共同列ofType:集合中元素的类型select:要连接的查询8、Mybatis配置一对一?<association property="topicType" select="selectType" column="topics_type_id" javaType="com.tmf.bbs.pojo.Type"/>property:属性名select:要连接的查询column:共同列javaType:集合中元素的类型9 、${} 和 #{}的区别?${}:简单字符串替换,把${}直接替换成变量的值,不做任何转换,这种是取值以后再去编译SQL语句。#{}:预编译处理,sql中的#{}替换成?,补全预编译语句,有效的防止Sql语句注入,这种取值是编译好SQL语句再取值。总结:一般用#{}来进行列的代替10、获取上一次自动生成的主键值?select last _insert_id()11、Mybatis如何分页,分页原理?RowBounds对象分页在Sql内直接书写,带有物理分页12、Mybatis工作原理? 原理:通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件中构建出SqlSessionFactory。SqlSessionFactory开启一个SqlSession,通过SqlSession实例获得Mapper对象并且运行Mapper映射的Sql语句。完成数据库的CRUD操作和事务提交,关闭SqlSession。四、结语前面如有不正确的地方还希望大家多多指教,希望和志同道合的朋友一起学习,一起进步,先更新到这里,下次继续补充。
面向对象编程的基本理念与核心设计思想解释下多态性(polymorphism),封装性(encapsulation),内聚(cohesion)以及耦合(coupling)。继承(Inheritance)与聚合(Aggregation)的区别在哪里。你是如何理解干净的代码(Clean Code)与技术负载(Technical Debt)的。描述下常用的重构技巧。阐述下 SOLID 原则。其他的譬如 KISS,DRY,YAGNI 等原则又是什么含义。什么是设计模式(Design Patterns)?你知道哪些设计模式?你有了解过存在哪些反模式(Anti-Patterns)吗?你会如何设计登陆舰/数学表达式计算程序/一条龙?你知道哪些基本的排序算法,它们的计算复杂度如何?在给定数据的情况下你会倾向于使用哪种算法呢?尝试编写如下代码:计算指定数字的阶乘开发 Fizz Buzz 小游戏倒转句子中的单词回文字符串检测枚举给定字符串的所有排列组合Java 核心概念equals 与 hashCode 的异同点在哪里?Java 的集合中又是如何使用它们的。描述下 Java 中集合(Collections),接口(Interfaces),实现(Implementations)的概念。LinkedList 与 ArrayList 的区别是什么?基础类型(Primitives)与封装类型(Wrappers)的区别在哪里?final 与 static 关键字可以用于哪里?它们的作用是什么?阐述下 Java 中的访问描述符(Access Modifiers)。描述下 String,StringBuilder 以及 StringBuffer 区别。接口(Interface)与抽象类(Abstract Class)的区别在哪里。覆盖(Overriding)与重载(OverLoading)的区别在哪里。异常分为哪几种类型?以及所谓的handle or declare原则应该如何理解?简述垃圾回收器的工作原理。你是如何处理内存泄露或者栈溢出问题的?如何构建不可变的类结构?关键点在哪里?什么是 JIT 编译?Java 8 / Java 7 为我们提供了什么新功能?即将到来的 Java 9 又带来了怎样的新功能?Hibernate / 数据库请解释下 ORM。简述下 Hibernate 的优劣特性。Hibernate 与 JPA 区别在哪?Hibernate 最新版提供了哪些特性?什么是懒加载(Lazy Loading)?什么是 N+1 难题?介绍一些熟悉的 Hibernate 注释。简介下 Hibernate Session 与 SessionFactory。Entity Beans 的状态有哪些。Hibernate 中的缓存分为几层。Hibernate 中事务的支持分为几级?什么是乐观锁(Optimistic Locking)?简述下 ACID 原则。简述下数据库正则化(Normalizations)。请介绍下你日常工作中优化慢查询(Slow Query)的策略。Spring新版的 Spring 中有哪些新特性?介绍下 Spring 的优势与缺陷。什么是控制反转(Inversion of Control)与依赖注入(Dependency Injection)?你用过哪些 Spring 的模块?Spring 中是如何使用依赖注入的?Spring 中提供了几种自动注入的机制?介绍下 Spring MVC。Spring 中 Scopes 有哪些?Spring 中 Bean 的生命周期包含哪些步骤?Spring Bean 与 EJB Bean 的区别在哪里?其他主题介绍下切面编程(Aspect Oriented Programming)。概述下 GET 与 POST 的区别。Web Server、Web Container 与 Application Server 的区别是什么?简要介绍下从浏览器输入 URL 开始到获取到请求界面之后 Java Web 应用中发生了什么。什么是 N 层架构?微服务(MicroServices)与巨石型应用(Monolithic Applications)之间的区别在哪里?你知道哪些商业级设计模式?你是如何测试一个应用的?知道哪些测试框架?你是如何测试单个方法的?在你的职业生涯中,算得上最困难的技术挑战是什么?什么是领域驱动开发(Domain Driven Development)?介绍下一些你最爱的 IDE 的常用插件。除了 IDE 之外,你的日常工作中还会用到哪些工具?你使用什么版本管理工具?分支(Branch)与标签(Tag)之间的区别在哪里?你常用的持续集成(Continuous Integration)、静态代码分析(Static Code Analysis)工具有哪些?
1、什么是线程池线程池的基本思想是一种对象池,在程序启动时就开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。2、使用线程池的好处减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。运用线程池能有效的控制线程最大并发数,可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。对线程进行一些简单的管理,比如:延时执行、定时循环执行的策略等,运用线程池都能进行很好的实现3、线程池的主要组件  一个线程池包括以下四个基本组成部分:线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;工作线程(WorkThread):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。4、ThreadPoolExecutor类讲到线程池,要重点介绍java.uitl.concurrent.ThreadPoolExecutor类,ThreadPoolExecutor线程池中最核心的一个类,ThreadPoolExecutor在JDK中线程池常用类UML类关系图如下: 我们可以通过ThreadPoolExecutor来创建一个线程池 new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime,milliseconds,runnableTaskQueue, threadFactory,handler);1. 创建一个线程池需要输入几个参数corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字,Debug和定位问题时非常又帮助。RejectedExecutionHandler(拒绝策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。n AbortPolicy:直接抛出异常。keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。2. 向线程池提交任务我们可以通过execute()或submit()两个方法向线程池提交任务,不过它们有所不同execute()方法没有返回值,所以无法判断任务知否被线程池执行成功threadsPool.execute(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stub}});submit()方法返回一个future,那么我们可以通过这个future来判断任务是否执行成功,通过future的get方法来获取返回值try {Object s = future.get();} catch (InterruptedException e) {// 处理中断异常} catch (ExecutionException e) {// 处理无法执行任务异常} finally {// 关闭线程池executor.shutdown();}3. 线程池的关闭我们可以通过shutdown()或shutdownNow()方法来关闭线程池,不过它们也有所不同shutdown的原理是只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。shutdownNow的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。shutdownNow会首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表。4. ThreadPoolExecutor执行的策略  线程数量未达到corePoolSize,则新建一个线程(核心线程)执行任务线程数量达到了corePools,则将任务移入队列等待队列已满,新建线程(非核心线程)执行任务队列已满,总线程数又达到了maximumPoolSize,就会由(RejectedExecutionHandler)抛出异常新建线程 -> 达到核心数 -> 加入队列 -> 新建线程(非核心) -> 达到最大数 -> 触发拒绝策略5. 四种拒绝策略AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满,线程池默认策略DiscardPolicy:不执行新任务,也不抛出异常,基本上为静默模式。DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行CallerRunPolicy:拒绝新任务进入,如果该线程池还没有被关闭,那么这个新的任务在执行线程中被调用)5、Java通过Executors提供四种线程池CachedThreadPool():可缓存线程池。线程数无限制有空闲线程则复用空闲线程,若无空闲线程则新建线程 一定程序减少频繁创建/销毁线程,减少系统开销FixedThreadPool():定长线程池。可控制线程最大并发数(同时执行的线程数)超出的线程会在队列中等待ScheduledThreadPool():定时线程池。支持定时及周期性任务执行。SingleThreadExecutor():单线程化的线程池。有且仅有一个工作线程执行任务所有任务按照指定顺序执行,即遵循队列的入队出队规则1. newCachedThreadPoolnewCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程 public class ThreadPoolExecutorTest1 {public static void main(String[] args) {ExecutorService cachedThreadPool = Executors.newCachedThreadPool();for (int i = 0; i < 1000; i++) {final int index = i;try {Thread.sleep(index * 1000);} catch (Exception e) {e.printStackTrace();}cachedThreadPool.execute(new Runnable() {public void run() {System.out.println(Thread.currentThread().getName()+":"+index);}});}}} 2. newFixedThreadPoolnewFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待,指定线程池中的线程数量和最大线程数量一样,也就线程数量固定不变示例代码如下public class ThreadPoolExecutorTest {public static void main(String[] args) {ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);// 每隔两秒打印3个数for (int i = 0; i < 10; i++) {final int index = i;fixedThreadPool.execute(new Runnable() {public void run() {try {System.out.println(Thread.currentThread().getName()+":"+index);//三个线程并发Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}});}}} 3. newscheduledThreadPoolnewscheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下.表示延迟1秒后每3秒执行一次public class ThreadPoolExecutorTest3 {public static void main(String[] args) {ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);scheduledThreadPool.scheduleAtFixedRate(new Runnable() {public void run() {System.out.println(Thread.currentThread().getName() + ": delay 1 seconds, and excute every 3 seconds");}}, 1, 3, TimeUnit.SECONDS);// 表示延迟1秒后每3秒执行一次}}  4. newSingleThreadExecutornewSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行public class ThreadPoolExecutorTest4 {public static void main(String[] args) {ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();for (int i = 0; i < 10; i++) {final int index = i;singleThreadExecutor.execute(new Runnable() {public void run() {try {System.out.println(Thread.currentThread().getName() + ":" + index);Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});}}}结果依次输出,相当于顺序执行各个任务。使用JDK自带的监控工具来监控我们创建的线程数量,运行一个不终止的线程
微信公众号搜索 “ 程序精选 ” ,选择关注!
微信公众号搜 "程序精选"关注