前言
一、哪些集合类是线程安全的
- Vector:就比Arraylist多了个同步化机制(线程安全)。
- Stack:栈,也是线程安全的,继承于Vector。
- Hashtable:就比Hashmap多了个线程安全。
- ConcurrentHashMap:是一种高效但是线程安全的集合。
二、Java 中的线程池是如何实现的
创建一个阻塞队列来容纳任务,在第一次执行任务时创建足够多的线程,并处理任务,之后每个工作线程自动从任务队列中获取线程,直到任务队列中任务为0为止,此时线程处于等待状态,一旦有工作任务加入任务队列中,即刻唤醒工作线程进行处理,实现线程的可复用性。
线程池一般包括四个基本组成部分:
1、线程池管理器
用于创建线程池,销毁线程池,添加新任务。
2、工作线程
线程池中线程,可循环执行任务,在没有任务时处于等待状态。
3、任务队列
用于存放没有处理的任务,一种缓存机制。
4、任务接口
每个任务必须实现的接口,供工作线程调度任务的执行,主要规定了任务的开始和收尾工作,和任务的状态。
三、创建线程池的几个核心构造参数
// Java线程池的完整构造函数
public ThreadPoolExecutor(
int corePoolSize, // 线程池长期维持的最小线程数,即使线程处于Idle状态,也不会回收。
int maximumPoolSize, // 线程数的上限
long keepAliveTime, // 线程最大生命周期。
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列。当线程池中的线程都处于运行状态,而此时任务数量继续增加,则需要一个容器来容纳这些任务,这就是任务队列。
ThreadFactory threadFactory, // 线程工厂。定义如何启动一个线程,可以设置线程名称,并且可以确认是否是后台线程等。
RejectedExecutionHandler handler // 拒绝任务处理器。由于超出线程数量和队列容量而对继续增加的任务进行处理的程序。
)
四、线程池中的线程是怎么创建的?是一开始就随着线程池的启动创建好的吗?
线程池中的线程是在第一次提交任务submit时创建的
创建线程的方式有继承Thread和实现Runnable,重写run方法,start开始执行,wait等待,sleep休眠,shutdown停止。
1、newSingleThreadExecutor:单线程池。
顾名思义就是一个池中只有一个线程在运行,该线程永不超时,而且由于是一个线程,当有多个任务需要处理时,会将它们放置到一个无界阻塞队列中逐个处理,它的实现代码如下:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable()));
}
它的使用方法也很简单,下面是简单的示例:
public static void main(String[] args) throws ExecutionException,InterruptedException {
// 创建单线程执行器
ExecutorService es = Executors.newSingleThreadExecutor();
// 执行一个任务
Future<String> future = es.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return "";
}
});
// 获得任务执行后的返回值
System.out.println("返回值:" + future.get());
// 关闭执行器
es.shutdown();
}
2、newCachedThreadPool:缓冲功能的线程。
建立了一个线程池,而且线程数量是没有限制的(当然,不能超过Integer的最大值),新增一个任务即有一个线程处理,或者复用之前空闲的线程,或者重亲启动一个线程,但是一旦一个线程在60秒内一直处于等待状态时(也就是一分钟无事可做),则会被终止,其源码如下:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
这里需要说明的是,任务队列使用了同步阻塞队列,这意味着向队列中加入一个元素,即可唤醒一个线程(新创建的线程或复用空闲线程来处理),这种队列已经没有队列深度的概念了。
3、newFixedThreadPool:固定线程数量的线程池。
在初始化时已经决定了线程的最大数量,若任务添加的能力超出了线程的处理能力,则建立阻塞队列容纳多余的任务,其源码如下:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
上面返回的是一个ThreadPoolExecutor,它的corePoolSize和maximumPoolSize是相等的,也就是说,最大线程数量为nThreads。如果任务增长的速度非常快,超过了LinkedBlockingQuene的最大容量(Integer的最大值),那此时会如何处理呢?会按照ThreadPoolExecutor默认的拒绝策略(默认是DiscardPolicy,直接丢弃)来处理。
以上三种线程池执行器都是ThreadPoolExecutor的简化版,目的是帮助开发人员屏蔽过得线程细节,简化多线程开发。当需要运行异步任务时,可以直接通过Executors获得一个线程池,然后运行任务,不需要关注ThreadPoolExecutor的一系列参数时什么含义。当然,有时候这三个线程不能满足要求,此时则可以直接操作ThreadPoolExecutor来实现复杂的多线程计算。
newSingleThreadExecutor、newCachedThreadPool、newFixedThreadPool是线程池的简化版,而ThreadPoolExecutor则是旗舰版___简化版容易操作,需要了解的知识相对少些,方便使用,而旗舰版功能齐全,适用面广,难以驾驭。
五、spring mvc 和 struts 的区别是什么?
1、拦截机制的不同
Struts2是类级别的拦截,每次请求就会创建一个Action,和Spring整合时Struts2的ActionBean注入作用域是原型模式prototype,然后通过setter,getter吧request数据注入到属性。Struts2中,一个Action对应一个request,response上下文,在接收参数时,可以通过属性接收,这说明属性参数是让多个方法共享的。Struts2中Action的一个方法可以对应一个url,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了,只能设计为多例。
SpringMVC是方法级别的拦截,一个方法对应一个Request上下文,所以方法直接基本上是独立的,独享request,response数据。而每个方法同时又何一个url对应,参数的传递是直接注入到方法中的,是方法所独有的。处理结果通过ModeMap返回给框架。在Spring整合时,SpringMVC的Controller Bean默认单例模式Singleton,所以默认对所有的请求,只会创建一个Controller,有应为没有共享的属性,所以是线程安全的,如果要改变默认的作用域,需要添加@Scope注解修改。
Struts2有自己的拦截Interceptor机制,SpringMVC这是用的是独立的Aop方式,这样导致Struts2的配置文件量还是比SpringMVC大。
2、底层框架的不同
Struts2采用Filter(StrutsPrepareAndExecuteFilter)实现,SpringMVC(DispatcherServlet)则采用Servlet实现。Filter在容器启动之后即初始化;服务停止以后坠毁,晚于Servlet。Servlet在是在调用时初始化,先于Filter调用,服务停止后销毁。
3、性能方面
Struts2是类级别的拦截,每次请求对应实例一个新的Action,需要加载所有的属性值注入,SpringMVC实现了零配置,由于SpringMVC基于方法的拦截,有加载一次单例模式bean注入。所以,SpringMVC开发效率和性能高于Struts2。
4、配置方面
spring MVC和Spring是无缝的。从这个项目的管理和安全上也比Struts2高。
六、get 和 post 请求有哪些区别?
- get请求参数是连接在url后面的,而post请求参数是存放在requestbody内的;
- get请求因为浏览器对url长度有限制,所以参数个数有限制,而post请求参数个数没有限制;
- 因为get请求参数暴露在url上,所以安全方面post比get更加安全;
- get请求只能进行url编码,而post请求可以支持多种编码方式;
- get请求参数会保存在浏览器历史记录内,post请求并不会;
- get请求浏览器会主动cache,post并不会,除非主动设置;
- get请求产生1个tcp数据包,post请求产生2个tcp数据包;
- 在浏览器进行回退操作时,get请求是无害的,而post请求则会重新请求一次;
- 浏览器在发送get请求时会将header和data一起发送给服务器,服务器返回200状态码,而在发送post请求时,会先将header发送给服务器,服务器返回100,之后再将data发送给服务器,服务器返回200 OK;
七、请举例解释@Required 注解?
@Required注解应用于bean属性的setter方法,它表明影响的bean属性在配置时必须放在XML配置文件中。
八、请举例解释@Autowired 注解?
https://blog.csdn.net/qq_38243970/article/details/70847495
2020-10-11 21:20-21:40
九、请举例说明@Qualifier 注解?
如果在xml中定义了一种类型的多个bean,同时在java注解中又想把其中一个bean对象作为属性,那么此时可以使用@Qualifier加@Autowired来达到这一目的,若不加@Qualifier这个注解,在运行时会出现“ No qualifying bean of type [com.tutorialspoint.Student] is defined: expected single matching bean but found 2: student1,student2”这个异常。
十、如何使用 Spring Boot 实现异常处理?
1、使用 @ExceptionHandler 注解处理局部异常(只能处理当前controller中的ArithmeticException和NullPointerException异常,缺点就是只能处理单个controller的异常)
@Controller
public class ExceptionHandlerController {
@RequestMapping("/excep")
public String exceptionMethod(Model model) throws Exception {
String a=null;
System.out.println(a.charAt(1));
int num = 1/0;
model.addAttribute("message", "没有抛出异常");
return "index";
}
@ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
public String arithmeticExceptionHandle(Model model, Exception e) {
model.addAttribute("message", "@ExceptionHandler" + e.getMessage());
return "index";
}
}
2、使用 @ControllerAdvice + @ExceptionHandler 注解处理全局异常(value后面可以填写数组)
@ControllerAdvice
public class ControllerAdviceException {
@ExceptionHandler(value = {NullPointerException.class})
public String NullPointerExceptionHandler(Model model, Exception e) {
model.addAttribute("message", "@ControllerAdvice + @ExceptionHandler :" + e.getMessage());
return "index";
}
}
3、配置 SimpleMappingExceptionResolver 类处理异常(配置类)
@Configuration
public class SimpleMappingException {
@Bean
public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
//第一个参数为异常全限定名,第二个为跳转视图名称
mappings.put("java.lang.NullPointerException", "index");
mappings.put("java.lang.ArithmeticException", "index");
//设置异常与视图映射信息的
resolver.setExceptionMappings(mappings);
return resolver;
}
}
4、实现 HandlerExceptionResolver 接口处理异常
@Configuration
public class HandlerException implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", "实现HandlerExceptionResolver接口");
//判断不同异常类型,做不同视图跳转
if(ex instanceof NullPointerException){
modelAndView.setViewName("index");
}
if(ex instanceof ArithmeticException){
modelAndView.setViewName("index");
}
return modelAndView;
}
}
下一篇:Java面试题总结(附答案)