如何保障java线程安全
什么是线程安全?给一段线程不安全的代码分析
指某个函数 、函数库在多线程环境中被调用时,能够正确地处理各个线程的局部变量,使程序功能正确完成。 一般来说,线程安全的函数应该为每个调用它的线程分配专门的空间,来储存需要单独保存的状态,不依赖于“线程惯性”,把多个线程共享的变量正确对待,而且,线程安全的函数一般不应该修改全局对象。 很多C库代码不是线程安全的,在多线程环境中调用这些函数时,要进行特别的预防措施,或者寻找别的替代方案。
Thread safety 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.
非线程安全!=不安全
有人在使用过程中有一个不正确的观点:我的程序是多线程的,不能使用ArrayList要使用Vector,这样才安全。
非线程安全并不是多线程环境下就不能使用。注意我上面有说到:多线程操作同一个对象。注意是同一个对象。比如最上面那个模拟,就是在主线程中new的一个ArrayList然后多个线程操作同一个ArrayList对象。如果是每个线程中new一个ArrayList,而这个ArrayList只在这一个线程中使用,那么肯定是没问题的。
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.
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
package com.journaldev.threads; public class ThreadSafety { public static void main(String[] args) throws InterruptedException { ProcessingThread pt = new ProcessingThread(); Thread t1 = new Thread(pt, "t1"); t1.start(); Thread t2 = new Thread(pt, "t2"); t2.start(); //wait for threads to finish processing t1.join(); t2.join(); System.out.println("Processing count="+pt.getCount()); }
}
class ProcessingThread implements Runnable{ private int count;
@Override public void run() { for(int i=1; i< 5; i++){ processSomething(i); count++; } } public int getCount() { return this.count; }
private void processSomething(int i) { // processing some job try { Thread.sleep(i*1000); } catch (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.
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。