热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java多线程线程安全_Java中的线程安全

java多线程线程安全ThreadSafetyinJavaisaveryimportanttopic.Javaprovidesmulti-threadedenvironmentsu

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线程提供了多线程环境支持,我们知道从同一个对象创建的多个线程共享对象变量,当这些线程用于读取和更新共享数据时,这可能导致数据不一致

线程安全 (Thread Safety)

thread safe, thread safety, thread safety in java, thread safe java

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.

让我们用一个简单的程序检查一下,其中多个线程正在更新共享数据。

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也不会导致数据损坏。

Java中的线程安全 (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.

Java中的线程安全是使我们的程序在多线程环境中可以安全使用的过程&#xff0c;可以通过多种方法使程序线程安全。

  • Synchronization is the easiest and most widely used tool for thread safety in java.

    同步是Java中线程安全最简单&#xff0c;使用最广泛的工具。
  • Use of Atomic Wrapper classes from java.util.concurrent.atomic package. For example AtomicInteger

    java.util.concurrent.atomic包使用Atomic Wrapper类。 例如AtomicInteger
  • Use of locks from java.util.concurrent.locks package.

    使用java.util.concurrent.locks包中的锁。
  • Using thread safe collection classes, check this post for usage of ConcurrentHashMap for thread safety.

    使用线程安全收集类&#xff0c;请检查此帖子以了解ConcurrentHashMap的线程安全用法。
  • Using volatile keyword with variables to make every thread read the data from memory, not read from thread cache.

    将volatile关键字与变量一起使用&#xff0c;可使每个线程从内存中读取数据&#xff0c;而不是从线程缓存中读取数据。

Java同步 (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.

同步是我们可以用来实现线程安全性的工具&#xff0c;JVM保证同步的代码一次只能由一个线程执行。 java关键字sync用于创建同步代码&#xff0c;并且在内部使用Object或Class上的锁来确保只有一个线程在执行同步代码。

  • Java synchronization works on locking and unlocking of the resource before any thread enters into synchronized code, it has to acquire the lock on the Object and when code execution ends, it unlocks the resource that can be locked by other threads. In the meantime, other threads are in wait state to lock the synchronized resource.

    Java同步可在任何线程进入同步代码之前对资源进行锁定和解锁&#xff0c;它必须获得对Object的锁定&#xff0c;并且在代码执行结束时&#xff0c;它会解锁可以被其他线程锁定的资源。 同时&#xff0c;其他线程处于等待状态以锁定同步资源。
  • We can use synchronized keyword in two ways, one is to make a complete method synchronized and another way is to create synchronized block.

    我们可以通过两种方式使用synced关键字&#xff0c;一种是使完整的方法同步&#xff0c;另一种方法是创建同步块。
  • 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.

    同步方法时&#xff0c;它会锁定Object &#xff1b;如果方法是静态的&#xff0c;则它会锁定Class &#xff0c;因此&#xff0c;最佳做法始终是使用同步块来锁定方法中仅需要同步的部分。
  • While creating a 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.

    创建同步块时&#xff0c;我们需要提供获取锁定的资源&#xff0c;它可以是XYZ.class或该类的任何Object字段。
  • synchronized(this) will lock the Object before entering into the synchronized block.

    synchronized(this)将在进入同步块之前锁定对象。
  • 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 a lock on all the fields of the Object.

    您应该使用最低级别的锁定 &#xff0c;例如&#xff0c;如果一个类中有多个同步块&#xff0c;而其中一个正在锁定Object&#xff0c;则其他同步块也将不可用于其他线程执行。 当我们锁定一个对象时&#xff0c;它获得了对该对象所有字段的锁定。
  • Java Synchronization provides data integrity on the cost of performance, so it should be used only when it’s absolutely necessary.

    Java同步以性能为代价提供数据完整性&#xff0c;因此仅在绝对必要时才应使用它。
  • 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同步仅在同一个JVM中起作用&#xff0c;因此&#xff0c;如果您需要在多个JVM环境中锁定某些资源&#xff0c;则它将无法正常工作&#xff0c;因此您可能需要照顾一些全局锁定机制。
  • Java Synchronization could result in deadlocks, check this post about deadlock in java and how to avoid them.

    Java同步可能会导致死锁&#xff0c;请查看有关Java死锁以及如何避免死锁的文章。
  • Java synchronized keyword cannot be used for constructors and variables.

    Java同步关键字不能用于构造函数和变量。
  • It is preferable to create a dummy private Object to use for the 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 the parallel execution of the synchronized block.

    最好创建一个虚拟私有对象用于同步块&#xff0c;以使它的引用不能被任何其他代码更改。 例如&#xff0c;如果您有一个要在其上同步的Object的setter方法&#xff0c;则可以通过其他一些代码来更改其引用&#xff0c;从而导致并行执行同步块。
  • 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.

    我们不应该使用在常量池中维护的任何对象&#xff0c;例如&#xff0c;不应将String用于同步&#xff0c;因为如果任何其他代码也锁定在同一String上&#xff0c;它将尝试从String池获取对同一引用对象的锁定&#xff0c;并且即使两个代码无关&#xff0c;它们也会互相锁定。

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;就将线程名附加到数组值中。

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

Here is the output when I run the above program.

这是我运行上述程序时的输出。

Time taken&#61; 15005
[1:t2:t3, 2:t1, 3:t3, 4:t1:t3, 5:t2:t1, 6:t3]

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;方法以使程序具有线程安全性的方法。

private Object lock &#61; new Object();private void addThreadName(int i, String name) {synchronized(lock){strArr[i] &#61; strArr[i] &#43;":"&#43;name;}}

After this change, our program works fine and here is the correct output of the program.

进行此更改后&#xff0c;我们的程序可以正常工作&#xff0c;这是程序的正确输出。

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]

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多线程 线程安全



推荐阅读
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • (三)多表代码生成的实现方法
    本文介绍了一种实现多表代码生成的方法,使用了java代码和org.jeecg框架中的相关类和接口。通过设置主表配置,可以生成父子表的数据模型。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
author-avatar
手机用户2502910213
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有