什么是线程安全?给一段线程不安全的代码分析
指某个函数 、函数库在多线程环境中被调用时,能够正确地处理各个线程的局部变量,使程序功能正确完成。
一般来说,线程安全的函数应该为每个调用它的线程分配专门的空间,来储存需要单独保存的状态,不依赖于“线程惯性”,把多个线程共享的变量正确对待,而且,线程安全的函数一般不应该修改全局对象。
很多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 ProcessingThread pt = Thread t1 = new t1.start(); Thread t2 = new t2.start(); //wait for threads to t1.join(); t2.join(); System.out.println("Processing } } class ProcessingThread implements Runnable{ private int count; @Override public void run() { for(int i=1; i< 5; processSomething(i); count++; } } public int getCount() { return this.count; } private void processSomething(int i) { // processing some try { Thread.sleep(i*1000); } catch 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.
如何保障java线程安全