Java开发代码规范之编程规约(八)——并发处理

文章通过学习《阿里巴巴Java开发手册》整理

单例对象

获取单例对象需要保证线程安全,其中的方法也要保证线程安全。
资源驱动类、工具类、单例工厂类都需要注意。

线程创建

创建线程或线程池时指定有意义的线程名称,方便出错时回溯。

线程池

线程资源必须通过线程池提供,不允许在应用中自行显示创建线程。
说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或“过度切换”的问题。

线程池创建

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式能更加明确线程池的运行规则,规避资源耗尽的风险。

SimpleDateFormat

SimpleDateFormat是线程不安全的类,一般不要定义为static变量,如果定义为static,必须加锁,或者使用DateUtils工具类。
正例:注意线程安全,使用DateUtils。或如下处理:

private static final ThreadLocal df = new ThreadLocal() {
	@Override
	protected DateFormat initialValue() {
		return new SimpleDateFormat("yyyy-MM-dd");
	}
}

说明:如果是jdk8的应用,可以使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFormat。

高并发

高并发时,同步调用应该去考量锁的性能消耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不用类锁。

死锁

对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则会造成死锁。
说明:线程1需要对表A、B、C依次全部加锁后才可以进行更新操作,那么线程2 的加锁顺序也必须是A、B、C,否则可能出现死锁。

并发修改同一记录

并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用version作为更新数据。
说明:如果每次访问冲突概率小于20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于3次。

多线程并行处理定时任务

多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用SchedledExecutorService则没有这个问题。

使用CountDownLatch进行异步转同步操作

使用CountDownLatch进行异步转同步操作,每个线程退出前必须调用countDown方法,线程执行代码注意catch异常,确保countDown方法被执行到,避免主线程无法执行到await方法,直到超时才返回结果。
说明:子线程抛出异常堆栈,不能在主线程try-catch到。

你可能感兴趣的:(Java,Code,Standard)