首页 > 编程语言 >一文读懂Java线程安全

一文读懂Java线程安全

时间:2024-06-21 16:56:51浏览次数:15  
标签:lang Java Thread Utf8 .# 读懂 线程 java

什么是线程安全性

《Java Concurrency In Practice》对线程安全的定义如下:

当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用方代码不作其他的协调,这个类的行为仍是正确的,那么称这个类是线程安全的。

简单理解就是,多线程环境下访问这个对象,我们不必考虑对象里面方法间协调的问题,对象的行为依然正确。通常这些类自己已经做好了同步等工作,比如,并发访问对象的共享变量时加上锁等同步机制。

多线程环境下,如果没有正确的同步机制,非常容易出错,比如非原子性操作导致的并发操作结果错误、线程运行顺序导致的程序错误、线程活跃性,如死锁、活锁、线程饥饿等都会导致程序结果未达预期。下面简单介绍下各种情况导致的错误及解决方案。

原子性

非原子操作在多线程程序中出错经典的例子,如,i++操作。看似一个操作,实际分成了三步,先从内存中读取,然后增加,最后写回内存。下面看个例子:

/**
 * @author kangming.ning
 * @date 2023-02-16
 * @since 1.0
 **/
public class SelfAddTest {

    static int i;

    public static void main(String[] args) throws InterruptedException {
        Runnable runnable=()->{
            selfAdd();
        };

        Thread thread1=new Thread(runnable);
        thread1.start();
        Thread thread2=new Thread(runnable);
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(i);
    }

    private static void selfAdd(){
        for (int j=0;j<10000;j++){
            i++;
        }
    }
}

结果打印不定,通常小于预期值2000。这说明程序出错了。下面我们反编译class文件,看生成的汇编代码,看看i++到底生成了哪些指令(javap )

输入指令:javap -verbose -c -l -private .\SelfAddTest.class

Last modified 2023-2-17; size 1614 bytes
  MD5 checksum 96b2b83020dc44d8755a9c241ba70d76
  Compiled from "SelfAddTest.java"
public class com.kmning.wallet.myconcurrent.SelfAddTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #12.#39        // java/lang/Object."<init>":()V
   #2 = InvokeDynamic      #0:#44         // #0:run:()Ljava/lang/Runnable;
   #3 = Class              #45            // java/lang/Thread
   #4 = Methodref          #3.#46         // java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
   #5 = Methodref          #3.#47         // java/lang/Thread.start:()V
   #6 = Methodref          #3.#48         // java/lang/Thread.join:()V
   #7 = Fieldref           #49.#50        // java/lang/System.out:Ljava/io/PrintStream;
   #8 = Fieldref           #11.#51        // com/kmning/wallet/myconcurrent/SelfAddTest.i:I
   #9 = Methodref          #52.#53        // java/io/PrintStream.println:(I)V
  #10 = Methodref          #11.#54        // com/kmning/wallet/myconcurrent/SelfAddTest.selfAdd:()V
  #11 = Class              #55            // com/kmning/wallet/myconcurrent/SelfAddTest
  #12 = Class              #56            // java/lang/Object
  #13 = Utf8               i
  #14 = Utf8               I
  #15 = Utf8               <init>
  #16 = Utf8               ()V
  #17 = Utf8               Code
  #18 = Utf8               LineNumberTable
  #19 = Utf8               LocalVariableTable
  #20 = Utf8               this
  #21 = Utf8               Lcom/kmning/wallet/myconcurrent/SelfAddTest;
  #22 = Utf8               main
  #23 = Utf8               ([Ljava/lang/String;)V
  #24 = Utf8               args
  #25 = Utf8               [Ljava/lang/String;
  #26 = Utf8               runnable
  #27 = Utf8               Ljava/lang/Runnable;
  #28 = Utf8               thread1
  #29 &#

标签:lang,Java,Thread,Utf8,.#,读懂,线程,java
From: https://blog.csdn.net/u012882823/article/details/139865328

相关文章

  • 一文读懂Java多线程并发之内存模型
     什么是内存模型?Java内存模型(JavaMemoryModel)描述了Java编程语言中的线程如何与内存进行交互,是和多线程相关的一组规范,需要各个JVM的实现来遵守JMM规范,以便于开发者可以利用这些规范,更方便地开发多线程程序。有了这些规范,即便同一个程序在不同操作系统的虚拟机上运行......
  • 等待执行完后一起收集的多线程
    多线程执行importorg.springframework.scheduling.annotation.Async;importorg.springframework.stereotype.Service;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.ExecutionExceptio......
  • JavaScript状态数据
    最近需要做一个三维场景切换的功能,切换场景后,还可以进行二三维模式的切换,二三维切换时,要定位到当前场景视角,那么场景的视角参数信息就需要保存到状态数据中,以供二三维场景切换时使用。项目是用vue做的,这里并没有使用vue的状态管理库,我是这样实现的:定义状态数据sceneInfolets......
  • 我一直看不明白:“C++会被java/python等这些语言替代”
    在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「C++的资料从专业入门到高级教程」,点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!有些程序,是既可以用c++编写,也可以用java/python编写。如果这类程序以前主要是由c++编写,后来逐渐变成主要......
  • JavaScript的学习之旅之基本数据类型
    一、字面量(常量)和变量字面量:不可变的数据,一般位于等式的右边变量:可变的数据,位于等式的左边<script> //声明一个变量 //用关键字var声明 vara; //要为变量赋值 a=456 a=678 //声明和赋值可以同时进行 varb=34; console.log(b);</script>二、标识符......
  • JAVA SSE 服务端单向消息通知
    工作记录关于只需要服务端向web端单向通知的技术SSE的技术落地总结最近有个需求是关于消息的单向通知,原本考虑用websocket,但是技术经理认为太重,建议采用SSE.查阅相关技术后结合实际业务需要新建了一个工具类@Component@Slf4jpublicclassSSEUtils{privatefinalMap<......
  • 一个练习项目,好玩的bbs-java
    java这个我是用springboot做的目录结构   application.ymlspring:datasource:driver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://127.0.0.1:3306/my_bbs?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2b8&am......
  • Java语言设计
    第一章:Java环境搭建Java是一种计算机编程语言;除了java编程语言,还有很多的编程语言:c、c++、c#、python等不同编程语言类比于不同国家语言;每个编程语言的语法不同;应用场景不同Java是一个用于后端开发的编程语言 一、Java历史1.1995年,sun公司推出的一款面向对象的编程语......
  • Java语言设计
    第二章:变量、数据类型、运算符、表达式一、变量1.概念:计算机中的一块内存空间,存储数据的基本单元2.变量的组成部分:数据类型、变量名、数据3.语法:(1)先声明,再赋值:  数据类型变量名;//声明  变量名=值; //赋值   (2)声明的同时并赋值:  数......
  • Java语言设计3
    第三章:分支结构一、if分支结构1.基本if结构:(1)语法:  if(判断条件/布尔表达式){    //语句  }(2)执行原理:如果判断条件成立,则执行{}中的语句2.基本if结构2(1)语法:  if(判断条件/布尔表达式){    //语句1  }else{    //......