什么是线程安全?如何保证线程安全?Java 中保证线程安全的方法有哪些?【重要】

简介: 什么是线程安全?如何保证线程安全?Java 中保证线程安全的方法有哪些?【重要】

一、什么是线程安全?

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

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

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

 

二、如何保证线程安全?

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

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

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

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

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

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

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

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

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

1. 针对原子性:

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

2. 针对可见性:

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

3. 针对重排序问题:

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

相关文章
|
1天前
|
存储 缓存 前端开发
Java八股文面试之多线程篇
Java八股文面试之多线程篇
9 0
Java八股文面试之多线程篇
|
1天前
|
Java
java面试之线程八锁
java面试之线程八锁
7 0
|
1天前
|
存储 SQL 安全
Java共享问题 、synchronized 线程安全分析、Monitor、wait/notify以及锁分类
Java共享问题 、synchronized 线程安全分析、Monitor、wait/notify以及锁分类
11 0
|
1天前
|
Java 调度 Windows
Java面试之程序、进程、线程、管程和并发、并行的概念
Java面试之程序、进程、线程、管程和并发、并行的概念
7 0
|
10天前
|
存储 测试技术
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
15 0
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
|
11天前
|
数据采集 Java Unix
10-多线程、多进程和线程池编程(2)
10-多线程、多进程和线程池编程
|
11天前
|
安全 Java 调度
10-多线程、多进程和线程池编程(1)
10-多线程、多进程和线程池编程
|
15天前
|
存储 Linux C语言
c++进阶篇——初窥多线程(二) 基于C语言实现的多线程编写
本文介绍了C++中使用C语言的pthread库实现多线程编程。`pthread_create`用于创建新线程,`pthread_self`返回当前线程ID。示例展示了如何创建线程并打印线程ID,强调了线程同步的重要性,如使用`sleep`防止主线程提前结束导致子线程未执行完。`pthread_exit`用于线程退出,`pthread_join`用来等待并回收子线程,`pthread_detach`则分离线程。文中还提到了线程取消功能,通过`pthread_cancel`实现。这些基本操作是理解和使用C/C++多线程的关键。
|
18天前
|
安全 Java
【极客档案】Java 线程:解锁生命周期的秘密,成为多线程世界的主宰者!
【6月更文挑战第19天】Java多线程编程中,掌握线程生命周期是关键。创建线程可通过继承`Thread`或实现`Runnable`,调用`start()`使线程进入就绪状态。利用`synchronized`保证线程安全,处理阻塞状态,注意资源管理,如使用线程池优化。通过实践与总结,成为多线程编程的专家。
|
18天前
|
Java 开发者
告别单线程时代!Java 多线程入门:选继承 Thread 还是 Runnable?
【6月更文挑战第19天】在Java中,面对多任务需求时,开发者可以选择继承`Thread`或实现`Runnable`接口来创建线程。`Thread`继承直接但限制了单继承,而`Runnable`接口提供多实现的灵活性和资源共享。多线程能提升CPU利用率,适用于并发处理和提高响应速度,如在网络服务器中并发处理请求,增强程序性能。不论是选择哪种方式,都是迈向高效编程的重要一步。