Java线程安全

文章来自什么是线程安全?如何保证线程安全?Java 中保证线程安全的方法有哪些?【重要】-阿里云开发者社区 (aliyun.com)

什么是线程安全?

简单来说,线程安全是多个线程访问同一段代码,不会造成不确定的结果。

线程安全就是多线程访问时,采用了加锁机制,同一时刻有且只有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再对共享数据进行操作,确保不会出现数据不一致或者数据污染。

线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。

如何保证线程安全?

先说一下造成线程不安全的三个原因,主要是:

原子性:一个或多个线程操作 CPU 执行的过程中被中断,互斥性称为操作的原子性。

可见性:一个线程对共享变量的修改,其他线程不能立刻看到。

有序性:程序执行的顺序没有按照代码的先后顺序执行。

可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(也就是其他线程获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作,从而引起不一致。

这里解释一下有序性,为什么程序执行的顺序会和代码的执行顺序不一致。因为 java 平台的两种编译器:静态编译器(javac)和动态编译器(jit:just in time)。

  • 静态编译器是将.java 文件编译成.class 文件,之后便可以解释执行。
  • 动态编译器是将.class 文件编译成机器码,之后再由 jvm 运行。

有时候,动态编译器为了程序的整体性能会对指令进行重排序,虽然重排序可以提升程序的性能,但是重排序之后会导致源代码中指定的内存访问顺序与实际的执行顺序不一样,就会出现线程不安全的问题。

针对上述三个造成线程不安全的问题,java 程序如何保证线程安全呢?

1. 针对原子性:

JDK 里面提供了很多 atomic 类,比如 AtomicInteger、AtomicLong、AtomicBoolean 等等,这些类本身可以通过 CAS 来保证操作的原子性。另外 Java 也提供了各种锁机制,来保证锁内的代码块在同一时刻只能有一个线程执行,比如使用 synchronized 加锁,保证一个线程在对资源进行读、写时,其他线程不可对此资源进行操作,从而保证了线程的安全性。

CAS (compareAndSwap),中文叫比较交换,是一种无锁原子算法,映射到操作系统就是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,其实现方式是基于硬件平台的汇编指令,在intel的CPU中,使用的是cmpxchg指令,就是说CAS是靠硬件实现的,从而在硬件层面提升效率。

执行过程是这样:它包含 3 个参数 CAS(V,E,N),V表示要更新变量的值,E表示预期值,N表示新值。仅当 V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程完成更新,则当前线程则什么都不做,最后CAS 返回当前V的真实值。

当多个线程同时使用CAS 操作一个变量时,最多只有一个会胜出,并成功更新,其余均会失败。失败的线程不会挂起,仅是被告知失败,并且允许再次尝试(自旋),当然也允许实现的线程放弃操作。基于这样的原理,CAS 操作即使没有锁,也可以避免其他线程对当前线程的干扰。

与锁相比,使用CAS会使程序看起来更加复杂一些,但是使用无锁的方式完全没有锁竞争带来的线程间频繁调度的开销和阻塞,它对死锁问题天生免疫,因此他要比基于锁的方式拥有更优越的性能。

简单的说,CAS 需要你额外给出一个期望值,也就是你认为这个变量现在应该是什么样子的。如果变量不是你想象的那样,说明它已经被别人修改过了。你就需要重新读取,再次尝试修改就好了。
                        
原文链接:https://blog.csdn.net/qq_42370146/article/details/105559575

2. 针对可见性:

同样可以通过 synchronized 关键字加锁来解决,与此同时,java 还提供了 volatile 关键字,要优于 synchronized 的性能,同样可以保证修改对其他线程的可见性。volatile 一般用于对变量的写操作不依赖于当前值的场景中,比如状态标记量等。

3. 针对重排序问题:

可以通过 synchronized 关键字定义同步代码块或者同步方法保障有序性,另外也可以通过 Lock 接口来保障有序性。

  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值