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. deadlockrace 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多线程编码注意事项的更多相关文章

  1. ​结合异步模型,再次总结Netty多线程编码最佳实践

    更多技术分享可关注我 前言 本文重点总结Netty多线程的一些编码最佳实践和注意事项,并且顺便对Netty的线程调度模型,和异步模型做了一个汇总.原文:​​结合异步模型,再次总结Netty多线程编码最 ...

  2. Java多线程编程——进阶篇二

    一.线程的交互 a.线程交互的基础知识 线程交互知识点需要从java.lang.Object的类的三个方法来学习:    void notify()           唤醒在此对象监视器上等待的单个 ...

  3. android Java BASE64编码和解码二:图片的编码和解码

    1.准备工作 (1)在项目中集成 Base64 代码,集成方法见第一篇博文:android Java BASE64编码和解码一:基础 (2)添加 ImgHelper 工具类 package com.a ...

  4. java多线程系列6-阻塞队列

    这篇文章将使用经典的生产者消费者的例子来进一步巩固java多线程通信,介绍使用阻塞队列来简化程序 下面是一个经典的生产者消费者的例子: 假设使用缓冲区存储整数,缓冲区的大小是受限制的.缓冲区提供wri ...

  5. Java多线程初学者指南系列教程

    转自:http://developer.51cto.com/art/200911/162925.htm 51cto 本系列来自NokiaGuy的“真的有外星人吗”博客,系列名称为<Java多线程 ...

  6. Java语言编码规范(Java Code Conventions)

    Java语言编码规范(Java Code Conventions) 名称 Java语言编码规范(Java Code Conventions) 译者 晨光(Morning) 简介 本文档讲述了Java语 ...

  7. 关于JAVA多线程的那些事__初心者

    前言 其实事情的经过也许会复杂了点,这事还得从两个月前开始说.那天,我果断不干IT支援.那天,我立志要做一个真正的程序猿.那天,我26岁11个月.那天,我开始看Android.那天,我一边叨念着有朋自 ...

  8. 50个Java多线程面试题

    不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java 语言一个重要的特点就是内置了对并发的支持,让 Java 大受企业和程序员的欢迎.大多数待遇丰厚的 Java 开发职位都要求开发者 ...

  9. 细说Java多线程之内存可见性

    编程这些实践的知识技能,每一次学习使用可能都会有新的认识 一.细说Java多线程之内存可见性(数据挣用)         1.共享变量在线程间的可见性                共享变量:如果一个 ...

随机推荐

  1. Python_Tips[2] -> 函数延后估值及字节码分析

    函数延后估值及字节码分析 在一个循环中定义了函数 f 但是并未对其进行调用,在循环结束后调用,此时i值为3故最终3个函数输出均为9.而非1, 4, 9. 这是由于在定义闭包函数 f 时,传入变量 i, ...

  2. luogu P1164 小A点菜

    题目背景 uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家……餐馆,很低端的那种. uim指着墙上的价目表(太低级了没有菜单),说:“随便点”. 题目描述 不过uim由于买了一些辅(e ...

  3. linux 自动删除n天前文件

    现在系统每天生成一个日期文件夹,并压缩上传到ftp服务器,造成目录下文件太多,所以决定写个定时删除文件的任务 写脚本文件 find /home/data -mtime +90 -name " ...

  4. elasticsearch5.3.0 安装

    公司有项目打算用elasticsearch,所以研究了下,目前最新版本5.3.0 安装 1.下载包  https://artifacts.elastic.co/downloads/elasticsea ...

  5. Android SDK 目录说明

    Android SDK目录说明: AVD Manager.exe:虚拟机管理工具 SDK Manager.exe:sdk管理工具 tools目录:包括测试.调试.第三方工具.模拟器.数据管理工具等. ...

  6. u-boot-2010.3移植到Tiny6410问题总结

    问题1: u-boot-2010.3中nand_spl文件夹的作用:实现从Nandflash启动在编译是会建立几个链接文件,用这几个链接文件生成u-boot-spl-16k.bin nand_spl/ ...

  7. linux之网络配置相关

    ubuntu的网络配置文件在 /etc/network/intrfaces; suse的网络配置在          /etc/sysconfig/network/下面,每个网卡一个配置文件. int ...

  8. 脑科学对基金经理的八个启示 z

    脑科学对基金经理的八个启示 第一,总想要更多.人类大脑是在物资奇缺过程中进化的,所以获得任何“资源”,如食物.性.金钱等,都可以让人感觉良好,大脑也会鼓励我们继续下去. 事实上,可卡因等药物就是“绑架 ...

  9. ES6中的模板字符串---反引号``

    在react中,反引号``有特殊的含义. 如MDN中所述,模板字符串(Template literals)允许嵌入表达式,并且支持多行字符串和字符串插补特性.基本语法为以下几种: 其中第一行为最基本用 ...

  10. hibernate.cfg.xml配置文件对关联关系的书写技巧!

    以Department(部门类)和User(用户类)作为例子: 类图如下: 一般hibernate.cfg.xml的配置文件开头都是如下: <?xml version="1.0&quo ...