This article mainly introduces the analysis of Java thread safety and non-thread safety, involving the simulation of non-thread safety phenomena and the implementation of thread safety. Friends in need can refer to it and exchange and learn together.
What is the difference between ArrayList and Vector? What is the difference between HashMap and HashTable? What is the difference between StringBuilder and StringBuffer? These are common basic questions in Java interviews. Faced with such a question, the answer is: ArrayList is non-thread safe, Vector is thread safe; HashMap is non-thread safe, HashTable is thread safe; StringBuilder is non-thread safe, and StringBuffer is thread safe. Because this is what was written in the "Complete Java Interview Questions" I just memorized last night. At this point, if you continue to ask: What is thread safety? What is the difference between thread-safe and non-thread-safe? Under what circumstances are they used? Such a series of questions spurted out a lot of blood...
Non-thread-safe phenomenon simulation
Here we use ArrayList and Vector The reader will explain.
The following code creates a new non-thread-safe ArrayList in the main thread, and then opens 1000 threads to add elements to this ArrayList respectively. Each thread adds 100 elements, and so on for all threads. After execution is completed, what should be the size of this ArrayList? Should be 100,000?
public class Main { public static void main(String[] args) { // 进行10次测试 for(int i = 0; i < 10; i++) { test(); } } public static void test() { // 用来测试的List List<Object> list = new ArrayList<Object>(); // 线程数量(1000) int threadCount = 1000; // 用来让主线程等待threadCount个子线程执行完毕 CountDownLatch countDownLatch = new CountDownLatch(threadCount); // 启动threadCount个子线程 for(int i = 0; i < threadCount; i++) { Thread thread = new Thread(new MyThread(list, countDownLatch)); thread.start(); } try { // 主线程等待所有子线程执行完成,再向下执行 countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } // List的size System.out.println(list.size()); } } class MyThread implements Runnable { private List<Object> list; private CountDownLatch countDownLatch; public MyThread(List<Object> list, CountDownLatch countDownLatch) { this.list = list; this.countDownLatch = countDownLatch; } public void run() { // 每个线程向List中添加100个元素 for(int i = 0; i < 100; i++) { list.add(new Object()); } // 完成一个子线程 countDownLatch.countDown(); } }
The above was tested 10 times (why test 10 times? Because non-thread safety does not cause problems every time).
Output result:
99946 100000 100000 100000 99998 99959 100000 99975 100000 99996
The above output result shows that not every test result is 100000, there are several times At the end of the test, the size of the ArrayList was less than 100000, and an IndexOutOfBoundsException was even thrown from time to time. (If this phenomenon does not occur, you can try a few more times)
This is a problem caused by non-thread safety. If the above code is used in a production environment, there will be hidden dangers and bugs.
Then use the thread-safe Vector to test. Change the above code in one place, change
List<Object> list = new ArrayList<Object>();
in the test() method into
List<Object> list = new Vector<Object>();
and then run the program.
Output result:
100000 100000 100000 100000 100000 100000 100000 100000 100000 100000
After running a few more times, I found that they were all 100000, without any problems. Because Vector is thread-safe, there will be no problems when multiple threads operate on the same Vector object.
Try changing to LinkedList again. Similar problems with ArrayList will also occur, because LinkedList is also not thread-safe.
How to choose between the two
Non-thread safety means that problems may occur when multiple threads operate the same object. Thread safety means that there will be no problem when multiple threads operate the same object.
Thread safety must use many synchronized keywords for synchronization control, so it will inevitably lead to a reduction in performance.
So when using it, if multiple threads operate the same object, use the thread-safe Vector; otherwise, use the more efficient ArrayList.
Non-thread safety!=Unsafe
Someone has an incorrect view during use: I The program is multi-threaded and cannot use ArrayList. It is safe to use Vector.
Non-thread safety does not mean that it cannot be used in a multi-threaded environment. Note what I said above: multiple threads operate on the same object. Note that it is the same object. For example, the top simulation is a new ArrayList in the main thread and then multiple threads operate the same ArrayList object.
If it is a new ArrayList in each thread, and this ArrayList is only used in this thread, then there is definitely no problem.
Thread safety implementation
Thread safety is achieved through thread synchronization control, which is the synchronized keyword .
Here, I used code to implement a non-thread-safe counter and a thread-safe counter Counter, and conducted multi-thread tests on them.
Non-thread-safe counter:
public class Main { public static void main(String[] args) { // 进行10次测试 for(int i = 0; i < 10; i++) { test(); } } public static void test() { // 计数器 Counter counter = new Counter(); // 线程数量(1000) int threadCount = 1000; // 用来让主线程等待threadCount个子线程执行完毕 CountDownLatch countDownLatch = new CountDownLatch(threadCount); // 启动threadCount个子线程 for(int i = 0; i < threadCount; i++) { Thread thread = new Thread(new MyThread(counter, countDownLatch)); thread.start(); } try { // 主线程等待所有子线程执行完成,再向下执行 countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } // 计数器的值 System.out.println(counter.getCount()); } } class MyThread implements Runnable { private Counter counter; private CountDownLatch countDownLatch; public MyThread(Counter counter, CountDownLatch countDownLatch) { this.counter = counter; this.countDownLatch = countDownLatch; } public void run() { // 每个线程向Counter中进行10000次累加 for(int i = 0; i < 10000; i++) { counter.addCount(); } // 完成一个子线程 countDownLatch.countDown(); } } class Counter { private int count = 0; public int getCount() { return count; } public void addCount() { count++; } }
In the above test code, 1000 threads are opened, and each thread controls the counter After 10,000 accumulations, the final output result should be 10,000,000.
But the Counter in the above code is not controlled synchronously, so it is not thread-safe.
Output result:
9963727 9973178 9999577 9987650 9988734 9988665 9987820 9990847 9992305 9972233
Slightly modify the Counter into a thread-safe counter:
class Counter { private int count = 0; public int getCount() { return count; } public synchronized void addCount() { count++; } }
The above just adds synchronized synchronization control to the addCount() method, and it becomes a thread-safe counter. Execute the program again.
Output results:
10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000
Summary
The above is the detailed content of Detailed explanation of thread safety and non-thread safety in Java. For more information, please follow other related articles on the PHP Chinese website!