java多线程 线程安全
Thread Safety in Java is a very important topic. Java provides 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.
Java中的线程安全是一个非常重要的主题。 Java使用Java线程提供了多线程环境支持,我们知道从同一个对象创建的多个线程共享对象变量,当这些线程用于读取和更新共享数据时,这可能导致数据不一致 。
数据不一致的原因是因为更新任何字段值都不是原子过程,它需要三个步骤。 首先读取当前值,其次进行必要的操作以获取更新的值,第三次将更新的值分配给字段引用。
Let’s check this with a simple program where multiple threads are updating the shared data.
让我们用一个简单的程序检查一下,其中多个线程正在更新共享数据。
package com.journaldev.threads;public class ThreadSafety {public static void main(String[] args) throws InterruptedException {ProcessingThread pt &#61; new ProcessingThread();Thread t1 &#61; new Thread(pt, "t1");t1.start();Thread t2 &#61; new Thread(pt, "t2");t2.start();//wait for threads to finish processingt1.join();t2.join();System.out.println("Processing count&#61;"&#43;pt.getCount());}}class ProcessingThread implements Runnable{private int count;&#64;Overridepublic void run() {for(int i&#61;1; i <5; i&#43;&#43;){processSomething(i);count&#43;&#43;;}}public int getCount() {return this.count;}private void processSomething(int i) {// processing some jobtry {Thread.sleep(i*1000);} catch (InterruptedException e) {e.printStackTrace();}}}
In the above program for loop, count is incremented by 1 four times and since we have two threads, its value should be 8 after both the threads finished executing. But when you will run the above program multiple times, you will notice that count value is varying between 6,7,8. This is happening because even if count&#43;&#43; seems to be an atomic operation, its NOT and causing data corruption.
在上面的for循环程序中&#xff0c; count增加1到四倍&#xff0c;并且由于我们有两个线程&#xff0c;因此两个线程执行完后其值应为8。 但是当您多次运行上述程序时&#xff0c;您会注意到计数值在6,7,8之间变化。 发生这种情况是因为即使count &#43;&#43;似乎是一个原子操作&#xff0c;它的NOT也不会导致数据损坏。
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.
Java中的线程安全是使我们的程序在多线程环境中可以安全使用的过程&#xff0c;可以通过多种方法使程序线程安全。
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.
同步是我们可以用来实现线程安全性的工具&#xff0c;JVM保证同步的代码一次只能由一个线程执行。 java关键字sync用于创建同步代码&#xff0c;并且在内部使用Object或Class上的锁来确保只有一个线程在执行同步代码。
synchronized(this)
will lock the Object before entering into the synchronized block. synchronized(this)
将在进入同步块之前锁定对象。 Here are the code changes we need to do in the above program to make it thread-safe.
这是我们在上述程序中需要执行的代码更改&#xff0c;以使其具有线程安全性。
//dummy object variable for synchronizationprivate Object mutex&#61;new Object();...//using synchronized block to read, increment and update count value synchronouslysynchronized (mutex) {count&#43;&#43;;}
Let’s see some synchronization examples and what can we learn from them.
让我们看看一些同步示例&#xff0c;以及我们可以从中学到什么。
public class MyObject {// Locks on the object&#39;s monitorpublic synchronized void doSomething() { // ...}
}// Hackers code
MyObject myObject &#61; new MyObject();
synchronized (myObject) {while (true) {// Indefinitely delay myObjectThread.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 the system to go on deadlock and cause Denial of Service (DoS).
请注意&#xff0c;黑客的代码正在尝试锁定myObject实例&#xff0c;并且一旦获得了锁定&#xff0c;就永远不会释放它&#xff0c;从而导致doSomething&#xff08;&#xff09;方法在等待锁定时阻塞&#xff0c;这将导致系统进入死锁并导致拒绝服务&#xff08; DoS&#xff09;。
public class MyObject {public Object lock &#61; new Object();public void doSomething() {synchronized (lock) {// ...}}
}//untrusted codeMyObject myObject &#61; new MyObject();
//change the lock Object reference
myObject.lock &#61; new Object();
Notice that lock Object is public and by changing its reference, we can execute synchronized block parallel in multiple threads. A similar case is true if you have private Object but have a setter method to change its reference.
注意&#xff0c;锁对象是公共的&#xff0c;并且通过更改其引用&#xff0c;我们可以在多个线程中并行执行同步块。 如果您有私有Object但有一个setter方法来更改其引用&#xff0c;则情况类似。
public class MyObject {//locks on the class object&#39;s monitorpublic 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 a lock on the class monitor and not releasing it, it will cause deadlock and DoS in the system.
请注意&#xff0c;黑客代码已在类监视器上获得锁定&#xff0c;而没有释放它&#xff0c;这将导致系统中的死锁和DoS。
Here is another example where multiple threads are working on the same array of Strings and once processed, appending thread name to the array value.
这是另一个示例&#xff0c;其中多个线程正在相同的String数组上工作&#xff0c;并且一旦被处理&#xff0c;就将线程名附加到数组值中。
Here is the output when I run the above program. 这是我运行上述程序时的输出。 The String array values are corrupted because of shared data and no synchronization. Here is how we can change addThreadName() method to make our program thread-safe. 由于共享数据且没有同步&#xff0c;因此String数组值已损坏。 这是我们如何更改addThreadName&#xff08;&#xff09;方法以使程序具有线程安全性的方法。 After this change, our program works fine and here is the correct output of the program. 进行此更改后&#xff0c;我们的程序可以正常工作&#xff0c;这是程序的正确输出。 That’s all for thread safety in java, I hope you learned about thread-safe programming and using synchronized keyword. 这就是Java中线程安全的全部内容&#xff0c;希望您了解线程安全编程以及如何使用synced关键字。 翻译自: https://www.journaldev.com/1061/thread-safety-in-java java多线程 线程安全package com.journaldev.threads;import java.util.Arrays;public class SyncronizedMethod {public static void main(String[] args) throws InterruptedException {String[] arr &#61; {"1","2","3","4","5","6"};HashMapProcessor hmp &#61; new HashMapProcessor(arr);Thread t1&#61;new Thread(hmp, "t1");Thread t2&#61;new Thread(hmp, "t2");Thread t3&#61;new Thread(hmp, "t3");long start &#61; System.currentTimeMillis();//start all the threadst1.start();t2.start();t3.start();//wait for threads to finisht1.join();t2.join();t3.join();System.out.println("Time taken&#61; "&#43;(System.currentTimeMillis()-start));//check the shared variable value nowSystem.out.println(Arrays.asList(hmp.getMap()));}}class HashMapProcessor implements Runnable{private String[] strArr &#61; null;public HashMapProcessor(String[] m){this.strArr&#61;m;}public String[] getMap() {return strArr;}&#64;Overridepublic void run() {processArr(Thread.currentThread().getName());}private void processArr(String name) {for(int i&#61;0; i
Time taken&#61; 15005
[1:t2:t3, 2:t1, 3:t3, 4:t1:t3, 5:t2:t1, 6:t3]private Object lock &#61; new Object();private void addThreadName(int i, String name) {synchronized(lock){strArr[i] &#61; strArr[i] &#43;":"&#43;name;}}
Time taken&#61; 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]