Java保证线程安全的方式有哪些?

开发 前端
原子性和可见性比较容易理解,重点分析一下有序性。为什么程序执行的顺序会和代码的编写顺序不一致呢?

​ 一位工作5年的小伙伴面试时被问到这样一道题,说Java保证线程安全的方式有哪些?

今天,我给大家分享一下我的理解。

1、线程不安全的原因

回答这个问题之前,得先了解导致对象线程不安全的原因,主要有三个:

图片

  1. 原子性:一个或者多个操作在CPU执行过程中被中断。
  2. 可见性:一个线程对象共享变量的修改,导致另一个线程不能立即看到。
  3. 有序性:程序执行的顺序没有按照代码的先后顺序执行。

原子性和可见性比较容易理解,重点分析一下有序性。为什么程序执行的顺序会和代码的编写顺序不一致呢?这就得理解Java平台的两种编译器,静态编译器javac和动态编译器jit(just in time)。

图片

静态编译器是将.java文件编译成.class文件,JVM加载后就可以执行了。

而动态编译器是要将.class文件编译成机器码,再由JVM执行。有时候,动态编译器为了程序的整体性能会对指令进行重排序,但是,这又会导致源代码中指定的内存访问顺序和实际的执行顺序不一致,就会出现线程不安全的问题。

​2、如何保证线程安全

那么,针对以上三种情况,如何保证对象的线程安全呢?

图片

第1个,针对原子性。

(1)JDK提供了非常多的Atomic类,比如AtomicInteger、AtomicLong、AtomicBoolean等等。这些类都是通过CAS来保证原子性。

(2)另外,Java还提供了各种锁机制,来保证锁内的代码块在同一时刻只能被一个线程执行。比如用synchronized加锁。这样,就可以保证一个线程对资源进行读、写操作时,其他线程不可以对这个资源进行操作,从而保证了线程安全。

图片

第2个,针对可见性。

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

图片

第3个,针对有序性。

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

以上就是对Java保证线程安全的思路。当然,保证对象线程安全的方式还有很多,比如还可以使用ThreadLocal实现多个线程之间的数据隔离,使用final关键字等等,我这里就不一一列举了。最后,我留一个思考题,单用volatile关键字,能保证线程安全吗?

责任编辑:姜华 来源: Tom弹架构
相关推荐

2019-10-29 19:49:48

Java线程安全

2023-01-26 02:07:51

HashSet线程安全

2022-06-07 23:28:05

线程安全后端

2022-04-07 07:40:40

线程安全变量

2023-11-06 17:39:35

JavaArrayList线程

2016-01-06 15:00:49

2019-07-29 10:10:06

Java内存线程安全

2022-06-07 08:20:49

线程安全多线程

2019-07-15 10:49:16

区块链互联网云计算

2021-06-30 13:31:18

线程安全ThreadLocal

2023-10-18 09:27:58

Java编程

2020-04-24 10:19:18

物联网蓝牙数据

2019-09-08 17:02:38

2021-08-26 12:31:40

APP安全网络安全网络攻击

2020-06-12 10:03:01

线程安全多线程

2022-01-13 11:25:37

区块链游戏技术

2024-02-26 14:07:18

2021-05-27 08:21:51

JS继承对象

2023-05-08 16:29:34

2018-03-18 16:16:20

点赞
收藏

51CTO技术栈公众号