1.【强制】获取单例对象需要保证线程安全,其中的方法也要保证线程安全。
说明:资源驱动类、工具类、单例工厂类都需要注意。
解释:因为不是线程安全,会创建不出真正的单例,有可能一个类有多个对象。
2.【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。
正例:自定义线程工厂,并且根据外部特征进行分组,比如机房信息。
public class UserThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger nextId = new AtomicInteger(1);
- 定义线程组名称,在 jstack 问题排查时,非常有帮助
UserThreadFactory(String whatFeaturOfGroup) {
namePrefix = "From UserThreadFactory's " + whatFeaturOfGroup + "-Worker-";
}
@Override
public Thread newThread(Runnable task) {
String name = namePrefix + nextId.getAndIncrement(); Thread thread = new Thread(null, task, name, 0, false);
System.out.println(thread.getName());
return thread;
}
}
3.【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。
说明:线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。
解释:就像我们使用各种连接池一样,jdbc连接池等。池化很重要。tcp和http一个长连接好处:效率高,减少了创建和销毁链接,http每次都得重新建立连接。
4.【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2) CachedThreadPool和newScheduledThreadPool
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
解释:看代码。thread包下ExecutorsTest。点进去:newFixedThreadPool,发现其实Executor都是基于ThreadPoolExecutor创建的,只不过传入不同的参数,
参数含义如下:
corePoolSize:线程池中核心线程数量。
maximumPoolSize:线程池最大线程数量。
keepAliveTime:超出核心线程数量时,多出的空闲线程的存活时间。
unit: keepAliveTim