1. 线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
1)FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
图一:Executors 下创建 fixed thread pool从图一中我们可以看出,Executors.newFixedThreadPool 指定了线程的数量,但是由于使用的LinkedBlockingQueue,由于没有指定其容量大小,LinkedBlockingQueue会默认一个类似无限大小的容量(Integer.MAX_VALUE);如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。
图二:Executors 下创建 cached thread pool图二中,我们可以看出,Executors.newCachedThreadPool 并没有限定线程的数量
2. SimpleDateFormat 是线程不安全的类,一般不要定义为static变量,如果定义为 static,必须加锁,或者使用 DateUtils 工具类。
先来看看,怎么不安全了。
图三:线程不安全的simpleDateFormat 代码 图四:线程不安全的simpleDateFormat可以看到,在多线程的环境下,simpleDateFormat总是会出错。为什么SimpleDateFormat是不安全的?
图三:SimpleDateFormat 部分源码SimpleDateFormat不安全的主要原因就是,它包含了一个calendar的变量。该变量主要用于存储与日期有关的数据。但是在上图的parse方法中,在每establish一个calendar的时候,首先会清除原先的calendar,然后再来set新的。那么问题来了,如果有多个线程(thread1,thread2,这两个线程是共用一个calendar引用的),thread1准备返回新生成的calendar,但此时thread2 将calendar clear了,这样就会出现错误。
如何避免线程不安全呢?
1. 使用ThreadLocal 为每一个线程单独分配一个SimpleDateFormat. 如下图所示
图四:LocalThread 方式解决SimpleFormatDate线程不安全2. 使用LocalDate 和DateTimeFormatter
图五:DateTimeFormatter 解决线程不安全问题
网友评论