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 &lt; <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 &lt; 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.


About Pankaj

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.

最新文章

  1. 个人对B/S项目的一些理解(一)
  2. 46-df 显示磁盘空间的使用情况
  3. poj 1701【数学几何】
  4. Android如何缩减APK包大小
  5. 新的android studio创建的fragment工程跟老师讲的结构有区别
  6. Flume-NG(1.5版本)中SpillableMemoryChannel源码级分析
  7. DWZ的选择带回功能无法带回第一个value中的值
  8. EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配
  9. E - 食物链 poj1182
  10. Mindjet 一打开鼠标就动不了解决方法
  11. Oracle db中 CONNECT role的含义
  12. gif动图快速制作方法(附工具)(转)
  13. 我的Emacs配置文件
  14. 求第k小的元素
  15. PyQt:自定义QLineEdit禁止选中复制粘贴
  16. Spring 注解bean默认名称规则
  17. 开发winform程序,在拖拽控件大小时,VS会卡死
  18. pythonNet day02
  19. C#设计模式 —— 单例模式
  20. [C++] STACK_Principle

热门文章

  1. 杭电5137How Many Maos Does the Guanxi Worth
  2. 31.Intellij idea 的maven项目如何通过maven自动下载jar包
  3. vue+mui+html5+ plus开发的混合应用底部导航的显示与隐藏
  4. PS:切图
  5. angular路由(自带路由篇)
  6. JNDI学习总结(3)——Tomcat下使用C3P0配置JNDI数据源
  7. Android启动原理剖析
  8. 修改android的wifi客户端名称的两种方法
  9. code blocks主题颜色配置
  10. $routeParams 实现路由指定参数