写点什么

Java 面试题总结(乱序版,2020-09-29,3 分钟教会你什么线程安全以及如何实现线程安全

用户头像
极客good
关注
发布于: 刚刚

线程池中的线程是在第一次提交任务 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 秒内一直处于等待状态时(也就是一分钟无事可做),则会被终止,其源码如下:


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


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 请求有哪些区别?




  1. get 请求参数是连接在 url 后面的,而 post 请求参数是存放在 requestbody 内的;

  2. get 请求因为浏览器对 url 长度有限制,所以参数个数有限制,而 post 请求参数个数没有限制;

  3. 因为 get 请求参数暴露在 url 上,所以安全方面 post 比 get 更加安全;

  4. get 请求只能进行 url 编码,而 post 请求可以支持多种编码方式;

  5. get 请求参数会保存在浏览器历史记录内,post 请求并不会;

  6. get 请求浏览器会主动 cache,post 并不会,除非主动设置;

  7. get 请求产生 1 个 tcp 数据包,post 请求产生 2 个 tcp 数据包;

  8. 在浏览器进行回退操作时,get 请求是无害的,而 post 请求则会重新请求一次;

  9. 浏览器在发送 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";

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Java面试题总结(乱序版,2020-09-29,3分钟教会你什么线程安全以及如何实现线程安全