Thread Safety in Java(java中的线程安全)
Thread Safety in Java is a very important topic. Java provide multi-threaded environment support using Java Threads, we know that multiple threads created from same Object share object variables and this can lead to data inconsistency when the threads are used to read and update the shared data.
Thread Safety

The reason for data inconsistency is because updating any field value is not an atomic process, it requires three steps; first to read the current value, second to do the necessary operations to get the updated value and third to assign the updated value to the field reference.
Let’s check this with a simple program where multiple threads are updating the shared data.
Copy
package com.journaldev.threads;
public class ThreadSafety {
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> InterruptedException </span>{
ProcessingThread pt = <span class="hljs-keyword">new</span> ProcessingThread();
Thread t1 = <span class="hljs-keyword">new</span> Thread(pt, <span class="hljs-string">"t1"</span>);
t1.start();
Thread t2 = <span class="hljs-keyword">new</span> Thread(pt, <span class="hljs-string">"t2"</span>);
t2.start();
<span class="hljs-comment">//wait for threads to finish processing</span>
t1.join();
t2.join();
System.out.println(<span class="hljs-string">"Processing count="</span>+pt.getCount());
}
}
class ProcessingThread implements Runnable{
private int count;
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">1</span>; i < <span class="hljs-number">5</span>; i++){
processSomething(i);
count++;
}
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getCount</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.count;
}
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processSomething</span><span class="hljs-params">(<span class="hljs-keyword">int</span> i)</span> </span>{
<span class="hljs-comment">// processing some job</span>
<span class="hljs-keyword">try</span> {
Thread.sleep(i*<span class="hljs-number">1000</span>);
} <span class="hljs-keyword">catch</span> (InterruptedException e) {
e.printStackTrace();
}
}
}
In above program for loop, count is incremented by 1 four times and since we have two threads, it’s value should be 8 after both the threads finished executing. But when you will run above program multiple times, you will notice that count value is varying between 6,7,8. This is happening because even if count++ seems to be an atomic operation, its NOT and causing data corruption.
Thread Safety in Java
Thread safety in java is the process to make our program safe to use in multithreaded environment, there are different ways through which we can make our program thread safe.
- Synchronization is the easiest and most widely used tool for thread safety in java.
- Use of Atomic Wrapper classes from java.util.concurrent.atomic package. For example AtomicInteger
- Use of locks from java.util.concurrent.locks package.
- Using thread safe collection classes, check this post for usage of ConcurrentHashMap for thread safety.
- Using volatile keyword with variables to make every thread read the data from memory, not read from thread cache.
Java synchronized
Synchronization is the tool using which we can achieve thread safety, JVM guarantees that synchronized code will be executed by only one thread at a time. java keyword synchronized is used to create synchronized code and internally it uses locks on Object or Class to make sure only one thread is executing the synchronized code.
- Java synchronization works on locking and unlocking of resource, before any thread enters into synchronized code, it has to acquire lock on the Object and when code execution ends, it unlocks the resource that can be locked by other threads. In the mean time other threads are in wait state to lock the synchronized resource.
- We can use synchronized keyword in two ways, one is to make a complete method synchronized and other way is to create synchronized block.
- When a method is synchronized, it locks the Object, if method is static it locks the Class, so it’s always best practice to use synchronized block to lock the only sections of method that needs synchronization.
- While creating synchronized block, we need to provide the resource on which lock will be acquired, it can be XYZ.class or any Object field of the class.
synchronized(this)will lock the Object before entering into the synchronized block.- You should use the lowest level of locking, for example if there are multiple synchronized block in a class and one of them is locking the Object, then other synchronized blocks will also be not available for execution by other threads. When we lock an Object, it acquires lock on all the fields of the Object.
- Java Synchronization provides data integrity on the cost of performance, so it should be used only when it’s absolutely necessary.
- Java Synchronization works only in the same JVM, so if you need to lock some resource in multiple JVM environment, it will not work and you might have to look after some global locking mechanism.
- Java Synchronization could result in deadlocks, check this post about deadlock in java and how to avoid them.
- Java synchronized keyword cannot be used for constructors and variables.
- It is preferable to create a dummy private Object to use for synchronized block, so that it’s reference can’t be changed by any other code. For example if you have a setter method for Object on which you are synchronizing, it’s reference can be changed by some other code leads to parallel execution of the synchronized block.
- We should not use any object that is maintained in a constant pool, for example String should not be used for synchronization because if any other code is also locking on same String, it will try to acquire lock on the same reference object from String pool and even though both the codes are unrelated, they will lock each other.
Here is the code changes we need to do in above program to make it thread safe.
Copy
//dummy object variable for synchronization
private Object mutex=new Object();
...
//using synchronized block to read, increment and update count value synchronously
synchronized (mutex) {
count++;
}
Let’s see some synchronization examples and what can we learn from them.
Copy
public class MyObject {
// Locks on the object's monitor
public synchronized void doSomething() {
// ...
}
}
// Hackers code
MyObject myObject = new MyObject();
synchronized (myObject) {
while (true) {
// Indefinitely delay myObject
Thread.sleep(Integer.MAX_VALUE);
}
}
Notice that hacker’s code is trying to lock the myObject instance and once it gets the lock, it’s never releasing it causing doSomething() method to block on waiting for the lock, this will cause system to go on deadlock and cause Denial of Service (DoS).
Copy
public class MyObject {
public Object lock = new Object();
public void doSomething() {
synchronized (lock) {
// ...
}
}
}
//untrusted code
MyObject myObject = new MyObject();
//change the lock Object reference
myObject.lock = new Object();
Notice that lock Object is public and by changing it’s reference, we can execute synchronized block parallel in multiple threads. Similar case is true if you have private Object but have setter method to change it’s reference.
Copy
public class MyObject {
//locks on the class object's monitor
public static synchronized void doSomething() {
// ...
}
}
// hackers code
synchronized (MyObject.class) {
while (true) {
Thread.sleep(Integer.MAX_VALUE); // Indefinitely delay MyObject
}
}
Notice that hacker code is getting lock on class monitor and not releasing it, it will cause deadlock and DoS in the system.
Here is another example where multiple threads are working on same array of Strings and once processed, appending thread name to the array value.
Copy
package com.journaldev.threads;
import java.util.Arrays;
public class SyncronizedMethod {
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span>(<span class="hljs-params">String[] args</span>) throws InterruptedException </span>{
String[] arr = {<span class="hljs-string">"1"</span>,<span class="hljs-string">"2"</span>,<span class="hljs-string">"3"</span>,<span class="hljs-string">"4"</span>,<span class="hljs-string">"5"</span>,<span class="hljs-string">"6"</span>};
HashMapProcessor hmp = <span class="hljs-keyword">new</span> HashMapProcessor(arr);
Thread t1=<span class="hljs-keyword">new</span> Thread(hmp, <span class="hljs-string">"t1"</span>);
Thread t2=<span class="hljs-keyword">new</span> Thread(hmp, <span class="hljs-string">"t2"</span>);
Thread t3=<span class="hljs-keyword">new</span> Thread(hmp, <span class="hljs-string">"t3"</span>);
<span class="hljs-keyword">long</span> start = System.currentTimeMillis();
<span class="hljs-comment">//start all the threads</span>
t1.start();t2.start();t3.start();
<span class="hljs-comment">//wait for threads to finish</span>
t1.<span class="hljs-keyword">join</span>();t2.<span class="hljs-keyword">join</span>();t3.<span class="hljs-keyword">join</span>();
System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"Time taken= "</span>+(System.currentTimeMillis()-start));
<span class="hljs-comment">//check the shared variable value now</span>
System.<span class="hljs-keyword">out</span>.println(Arrays.asList(hmp.getMap()));
}
}
class HashMapProcessor implements Runnable{
<span class="hljs-keyword">private</span> String[] strArr = <span class="hljs-literal">null</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">HashMapProcessor</span>(<span class="hljs-params">String[] m</span>)</span>{
<span class="hljs-keyword">this</span>.strArr=m;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> String[] <span class="hljs-title">getMap</span>(<span class="hljs-params"></span>) </span>{
<span class="hljs-keyword">return</span> strArr;
}
@<span class="hljs-function">Override
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) </span>{
processArr(Thread.currentThread().getName());
}
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processArr</span>(<span class="hljs-params">String name</span>) </span>{
<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i < strArr.length; i++){
<span class="hljs-comment">//process data and append thread name</span>
processSomething(i);
addThreadName(i, name);
}
}
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addThreadName</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> i, String name</span>) </span>{
strArr[i] = strArr[i] +<span class="hljs-string">":"</span>+name;
}
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processSomething</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> index</span>) </span>{
<span class="hljs-comment">// processing some job</span>
<span class="hljs-keyword">try</span> {
Thread.sleep(index*<span class="hljs-number">1000</span>);
} <span class="hljs-keyword">catch</span> (InterruptedException e) {
e.printStackTrace();
}
}
}
Here is the output when I run above program.
Copy
Time taken= 15005
[1:t2:t3, 2:t1, 3:t3, 4:t1:t3, 5:t2:t1, 6:t3]
The String array values are corrupted because shared data and no synchronization. Here is how we can change addThreadName() method to make our program thread safe.
Copy
private Object lock = new Object();
private void addThreadName(int i, String name) {
synchronized(lock){
strArr[i] = strArr[i] +":"+name;
}
}
After this change, our program works fine and here is the correct output of the program.
Copy
Time taken= 15004
[1:t1:t2:t3, 2:t2:t1:t3, 3:t2:t3:t1, 4:t3:t2:t1, 5:t2:t1:t3, 6:t2:t1:t3]
That’s all for thread safety in java, I hope you learned about thread safe programming and using synchronized keyword.
If you have come this far, it means that you liked what you are reading. Why not reach little more and connect with me directly on Google Plus, Facebook or Twitter. I would love to hear your thoughts and opinions on my articles directly. Recently I started creating video tutorials too, so do check out my videos on Youtube.
About Pankaj
Thread Safety in Java(java中的线程安全)的更多相关文章
- 查看JAVA进程中哪个线程CPU消耗最高
一,在centos linux 上查看进程占用cpu过高 top shift+h 查看哪个进程程消耗最高 二,查看JAVA进程中哪个线程消耗最高 2.1 导出java运行的线程信息 ...
- 分析占用了大量 CPU 处理时间的是Java 进程中哪个线程
下面是详细步骤: 1. 首先确定进程的 ID ,可以使用 jps -v 或者 top 命令直接查看 2. 查看该进程中哪个线程占用大量 CPU,执行 top -H -p [PID] 结果如下: 可以发 ...
- 分析占用了大量CPU处理时间的是Java进程中哪个线程
下面是详细步骤: 1. 首先确定进程的 ID ,可以使用 jps -v 或者 top 命令直接查看 2. 查看该进程中哪个线程占用大量 CPU,执行 top -H -p [PID] 结果如下: 可以发 ...
- jps查看java进程中哪个线程在消耗系统资源
jps或ps -ef|grep java可以看到有哪些java进程,这个不用说了.但值得一提的是jps命令是依赖于/tmp下的某些文件 的. 而某些操作系统,定期会清理掉/tmp下的文件,导致jps无 ...
- JDK中ThreadDump诊断Java代码中的线程死锁问题
多线程的死锁..死锁不是死了而是线程互相等待... 在项目中可能就是在几十万行的代码中存在一个死锁的问题,如何发现这个问题并且解决这个问题. JavaJDK为我们提供了一个诊断工具叫做ThreadDu ...
- 查看java进程中哪个线程在消耗系统资源
1 top -p $pid -H 加上-H这个参数后,会列出有哪些线程.这样就可以看到哪个线程id最消耗系统资源了.看到的线程id是10进制的数字. 2 jstack $pid 可以打印出制定jav ...
- 在java程序中利用线程
package 第十一章; import java.awt.Button; import java.awt.Color; import java.awt.Font; import java.awt.F ...
- Java中的线程
http://hi.baidu.com/ochzqvztdbabcir/item/ab9758f9cfab6a5ac9f337d4 相濡以沫 Java语法总结 - 线程 一 提到线程好像是件很麻烦很复 ...
- Java多线程编程(1)--Java中的线程
一.程序.进程和线程 程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码.它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文 ...
- 额!Java中用户线程和守护线程区别这么大?
在 Java 语言中线程分为两类:用户线程和守护线程,而二者之间的区别却鲜有人知,所以本文磊哥带你来看二者之间的区别,以及守护线程需要注意的一些事项. 1.默认用户线程 Java 语言中无论是线程还是 ...
随机推荐
- 深入理解 GRE tunnel
深入理解 GRE tunnel 时间 2012-11-08 19:05:22 A Geek's Page 原文 http://wangcong.org/blog/archives/2149 主题 ...
- elasticsearch index 之 create index(二)
创建索引需要创建索引并且更新集群index matedata,这一过程在MetaDataCreateIndexService的createIndex方法中完成.这里会提交一个高优先级,AckedClu ...
- C++ 补课(二)
1,如果遇到派生类成员和基类成员的名称冲突的情况,程序会采用派生类成员执行相应的操作.如果需要使用基类中的同名成员,则必须在程序中使用全局分辨符“::” 虚基类 —— 派生类在继承基类时加入“virt ...
- Vue 导出表格为Excel
放法有多种,我这里是直接转JSON数据为Excel. 1.既然要使用,那首先当然是安装依赖,在终端命令输入: npm install -S file-saver xlsx npm install -D ...
- celery work logging 问题
celery 的日志里只输出日志 不输入标准打印
- 洛谷 P1911 L国的战斗之排兵布阵
P1911 L国的战斗之排兵布阵 题目背景 L国即将与I国发动战争!! 题目描述 L国的指挥官想让他的每一个军营都呈现出国徽形——“L”形(方向无所谓).当然,他的指挥营除外(这叫做个性),他想不出该 ...
- 洛谷 P3111 [USACO14DEC]牛慢跑Cow Jog_Sliver
P3111 [USACO14DEC]牛慢跑Cow Jog_Sliver 题目描述 The cows are out exercising their hooves again! There are N ...
- ZOJ 3587 Marlon's String 扩展KMP
链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3587 题意:给出两个字符串S和T.S,T<=100000.拿出 ...
- cocos2d-x 3.0 Loading界面实现
这个世界每一天都在验证我们的渺小,但我们却在努力创造,不断的在这生活的画卷中留下自己的脚印.或许等到我们老去的那一天,老得不能动仅仅能靠回顾的那一天.你躺在轮椅上,不断的回顾过去.相思的痛苦忘不了,相 ...
- [NOI.AC#40]Erlang
链接 题解 显然,最多抽2个集合 如果一直抽一个,前提是该集合有重复的,答案是不同元素的个数+1 如果抽两个,那么最坏情况下,在一个集合中抽到某一个数的次数是这个集合不同元素的个数(因为抽不到重复的) ...