java多线程编码注意事项
Sole purpose of using concurrency is to produce scalable and faster program. But always remember, speed comes after correctness. Your Java program must follow its invariant in all conditions, which it would, if executed in sequential manner. If you are new in concurrent Java programming, then take some time to get familiar yourself with different problem arises due to concurrent execution of program e.g. deadlock, race conditions, livelock, starvation etc.
1) Use Local Variables
Always try to use local variables instead of creating class or instance variables. Some time, developer use instance variable to save memory and reusing them, because they think creating local variable every time method invoked may take a lot of memory. One example of this is declaring Collection as member and reusing them by using clear() method. This introduce, a shared state in otherwise stateless class, which is designed for concurrent execution. Like in below code, where execute() method is called by multiple threads, and to implement a new functionality, you need a temp collection. In original code, a static List was used and developer's intention was to clear this at the end of execute() method for reuse. He thought that code is safe because of CopyOnWriteArrayList is thread-safe. What he failed to realize that, since this method get called by multiple threads, one thread may see data written by other thread in shared temp List. Synchronization provided by the list is not enough to protect method's invariant here.
public class ConcurrentTask{
private static List temp = Collections.synchronizedList(new ArrayList()); @Override
public void execute(Message message){
//I need a temporary ArrayList here, use local
//List temp = new ArrayList(); //add something from Message into List
temp.add("message.getId()");
temp.add("message.getCode()"); //combine id and code store result back to message
temp.clear(); // Let's resuse it
}
}
Problem :
One Message's data will go to other Message if two call of multiple thread interleaved. e.g. T1 adds Id from Message 1 then T2 adds Id from Message 2, which happens before List get cleared, so one of those message will have corrupted data.
Solution :
1) Add a synchronized block when one thread add something to temp list and clear() it. So that, no thread can access List until one is done with it. This will make that part single threaded and reduce overall application performance by that percentage.
2) Use a local List instead of a global one. Yes it will take few more bytes, but you are free from synchronization and code is much more readable. Also, you should be worrying too much about temporary objects, GC and JIT will take care of that.
This is just one of those cases, but I personally prefer a local variable rather than a member variable in multi-threading, until its part of design.
2) Prefer Immutable Classes
Another and most widely known Java multi-threading best practice is to prefer Immutable class. Immutable classes like String, Integer and other wrapper classes greatly simplify writing concurrent code in Java because you don't need to worry about there state. Immutable classes reduce amount of synchronization in code. Immutable classes, once created, can not be modified. One of the best example of this is java.lang.String, any modification on String e.g. converting it into uppercase, trim or substring would produce another String object, keeping original String object intact.
3) Minimize locking scope
Any code which is inside lock will not be executed concurrently and if you have 5% code inside lock than as per Amdahl's law, your application performance can not be improved more than 20 times. Main reason of this is those 5% code will always executed sequentially. You can reduce this amount by minimizing scope of locking, try to only lock critical sections. One of the best example of minimizing scope of locking is double checked locking idiom, which works by using volatile variable after Java 5 improvements on Java Memory model.
4) Prefer Thread Pool Executors instead of Threads
Creating Thread is expensive. If you want a scalable Java application, you need to use thread pool. Apart from cost, managing thread requires lots of boiler-plate code and mixing those with business logic reduces readability. Managing threads is a framework level task and should be left to Java or any proprietary framework you are using. JDK has a well built, rich and fully tested Thread pool also known as Executor framework, which should be utilized whenever needed.
5) Prefer Synchronization utility over wait notify
This Java multi-threading practice inspires from Java 1.5, which added lot of synchronization utilities like CycicBariier, CountDownLatch and Sempahore. You should always look to JDK concurrency and synchronization utility, before thinking of wait and notify. It's much easier to implement producer-consumer design with BlockingQueue than by implementing them using wait and notify. See those two links to compare yourself. Also, it's much easier to wait for 5 threads using CountDownLatch to complete there task rather than implementing same utility using wait and notify. Get yourself familiar with java.util.concurrent package for writing better Java concurrency code.
6) Prefer BlockingQueue for producer-consumer design
This multi-threading and concurrency best practice is related to earlier advice, but I have made it explicitly because of it's importance in real world concurrent applications. Many of concurrency problem are based on producer-consumer design pattern and BlockingQueue is best way to implement them in Java. Unlike Exchanger synchronization utility which can be used to implement single producer-consumer design, blocking queue can also handle multiple producer and consumers. See producer consumer with BlockingQueue in Java to learn more about this tip.
7) Prefer Concurrent Collections over synchronized Collection
As mentioned in my post about Top 5 Concurrent Collections in Java, they tend to provide more scalablility and performance than there synchronized counterpart. ConcurrentHashMap, which is I guess one of the most popular of all concurrent collection provide much better performance than synchronized HashMap or Hashtable if number of reader thread outnumber writers. Another advantage of Concurrent collections are that, they are built using new locking mechanism provided by Lock interface and better poised to take advantage of native concurrency construct provided by underlying hardware and JVM. In the same line, consider using CopyOnWriteArrayList in place of synchronized List, if List is mostly for reading purpose with rare updates.
8) Use Semaphore to create bounds
In order to build a reliable and stable system, you must have bounds on resources like database, file system, sockets etc. In no situation, your code create or use infinite number of resources. Semaphore is a good choice to have a limit on expensive resource like database connection, by the way leave that to your Connection pool. Semaphore is very helpful to creating bounds and blocking thread ifresource is not available. You can follow this tutorial to learn how to use use Semaphore in Java.
9) Prefer synchronized block over synchronized method
This Java multi-threading best practice is an extension of earlier best practice about minimizing scope of locking. Using synchronized block is one way to reduce scope of lock and it also allow you to lock on object other than "this", which represent current object. Today, your first choice should be atomic variable, followed by volatile variable if your synchronization requirement is satisfied by using them. Only if you need mutual exclusion you can consider using ReentrantLock followed by plain old synchronized keyword. If you are new to concurrency and not writing code for high frequency trading or any other mission critical application, stick with synchronized keyword because its much safer and easy to use. If you are new to Lock interface, see my tutorial how to use Lock in multi-threaded Java program for step by step guide.
10) Avoid Using static variables
As shown in first multi-threading best practice, static variables can create lots of issues during concurrent execution. If you happen to use static variable, consider it making static final constants and if static variables are used to store Collections like List or Map then consider using only read only collections. If you are thinking of reusing Collection to save memory, please see the example in first best practice to learn how static variables can cause problem in concurrent programs.
11) Prefer Lock over synchronized keyword
This is a bonus multi-threading best practice, but it's double edge sword at same time. Lock interface is powerful but every power comes with responsibility. Different locks for read and write operation allows to build scalable data structures like ConcurrentHashMap, but it also require lot of care during coding. Unlike synchronized keyword, thread doesn't release lock automatically. You need to call unlock() method to release a lock and best practice is to call it on finally block to ensure release in all conditions. here is an idiom to use explicitly lock in Java :
lock.lock();
try {
//do something ...
} finally {
lock.unlock();
}
By the way, this article is in line with 10 JDBC best practices and 10 code comments best practices, if you haven't read them already, you may find them worth reading. As some of you may agree that there is no end of best practices, It evolves and get popular with time. If you guys have any advice, experience, which can help any one writing concurrent program in Java, please share.
That's all on this list of Java multithreading and concurrency best practices. Once again, reading Concurrency Practice in Java and Effective Java is worth reading again and again. Also developing a sense for concurrent execution by doing code review helps a lot on visualizing problem during development. On closing note, let us know what best practices you follow while writing concurrent applications in Java?
Read more: http://javarevisited.blogspot.com/2015/05/top-10-java-multithreading-and.html#ixzz3uwId7oK7
java多线程编码注意事项的更多相关文章
- 结合异步模型,再次总结Netty多线程编码最佳实践
更多技术分享可关注我 前言 本文重点总结Netty多线程的一些编码最佳实践和注意事项,并且顺便对Netty的线程调度模型,和异步模型做了一个汇总.原文:结合异步模型,再次总结Netty多线程编码最 ...
- Java多线程编程——进阶篇二
一.线程的交互 a.线程交互的基础知识 线程交互知识点需要从java.lang.Object的类的三个方法来学习: void notify() 唤醒在此对象监视器上等待的单个 ...
- android Java BASE64编码和解码二:图片的编码和解码
1.准备工作 (1)在项目中集成 Base64 代码,集成方法见第一篇博文:android Java BASE64编码和解码一:基础 (2)添加 ImgHelper 工具类 package com.a ...
- java多线程系列6-阻塞队列
这篇文章将使用经典的生产者消费者的例子来进一步巩固java多线程通信,介绍使用阻塞队列来简化程序 下面是一个经典的生产者消费者的例子: 假设使用缓冲区存储整数,缓冲区的大小是受限制的.缓冲区提供wri ...
- Java多线程初学者指南系列教程
转自:http://developer.51cto.com/art/200911/162925.htm 51cto 本系列来自NokiaGuy的“真的有外星人吗”博客,系列名称为<Java多线程 ...
- Java语言编码规范(Java Code Conventions)
Java语言编码规范(Java Code Conventions) 名称 Java语言编码规范(Java Code Conventions) 译者 晨光(Morning) 简介 本文档讲述了Java语 ...
- 关于JAVA多线程的那些事__初心者
前言 其实事情的经过也许会复杂了点,这事还得从两个月前开始说.那天,我果断不干IT支援.那天,我立志要做一个真正的程序猿.那天,我26岁11个月.那天,我开始看Android.那天,我一边叨念着有朋自 ...
- 50个Java多线程面试题
不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java 语言一个重要的特点就是内置了对并发的支持,让 Java 大受企业和程序员的欢迎.大多数待遇丰厚的 Java 开发职位都要求开发者 ...
- 细说Java多线程之内存可见性
编程这些实践的知识技能,每一次学习使用可能都会有新的认识 一.细说Java多线程之内存可见性(数据挣用) 1.共享变量在线程间的可见性 共享变量:如果一个 ...
随机推荐
- 洛谷——2722总分 Score Inflation
题目背景 学生在我们USACO的竞赛中的得分越多我们越高兴. 我们试着设计我们的竞赛以便人们能尽可能的多得分,这需要你的帮助 题目描述 我们可以从几个种类中选取竞赛的题目,这里的一个"种类& ...
- 【bzoj1415】【聪聪和可可】期望dp(记忆化搜索)+最短路
[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=57148470 Descrition 首先很明显是 ...
- iOS开发 Swift开发数独游戏(一)
一.前言 我姥姥是一名退休数学老师,一直很喜欢玩数独游戏.我以前答应过她要给她写一个数独游戏.本来计划是写一个Android应用的,但恰好我学了好长时间iOS开发一直没做什么"大项目&quo ...
- iPhone 通过UIRequiredDeviceCapabilities指定程序适用于哪些设备
以前在itunes中查看某个应用时,会有说明信息,表明程序适用于ios 1.0,2.0,3.0什么的. 上周末将Key Manager上传到app store时,一直有个疑问,就是没有发现填写程序适用 ...
- 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-简介
本文翻译自Spring.NET官方文档Version 1.3.2. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助. 侵删. 简介 Aspect-Orie ...
- java的几个概念AOP、IOC、DI、DIP、工厂模式、IOC容器
1.AOP:面向切面编程 把一些公共类,比如日志类.安全类.数据库连接类.系统统一的认证.权限管理类.资源池(如数据库连接池的管理).性能监控等做成一个公共类,当其他类需要时,进行注入(调用).这样这 ...
- hibernate,mybatis,beetlsql 全面比較
这是我的一个综合评分.总共分为12个单项.每一个单项最高5分.最低0分. 注意.评价仅仅包括这些软件提供的标准功能,不包括第三方提供的功能,如代码生成等. 开发效率 hibernate 能获取数据库 ...
- 为什么重写equals方法时,要求必须重写hashCode方法?
1 equals方法 Object类中默认的实现方式是 : return this == obj .那就是说,只有this 和 obj引用同一个对象,才会返回true. 而我们往往需要用equ ...
- Linux修改SSH端口
为什么要修改默认22端口 最近公司ssh全部换掉了默认的22端口,主要是为了防止被黑客大规模的扫描. 修改步骤 如果有需要请关闭防火墙(防止改错端口无法登陆) 修改sshd_config vim /e ...
- ASP.NET MVC学习---(三)EF简单增删改查
那么现在我们已经大概从本质上了解了ef 巴拉巴拉说了一大堆之后 总算要进入ef的正题了 总在口头说也太不行了是吧~ 没错,现在要用ef进行一些实际的操作 做什么呢? 就做一个入门级的增删改查操作吧 废 ...