每日三个JAVA经典面试题(十八)

1.volatile 关键字的作用

在Java中,volatile关键字用于声明变量,以确保该变量的更新对所有线程都是可见的,即当一个线程修改了一个volatile变量的值,这个新值对于其他线程来说是立即得知的。volatile关键字有两个主要作用:

1. 保证内存可见性

在多线程环境中,为了提高性能,每个线程可能会将变量从主内存复制到CPU缓存中。如果一个线程修改了这个变量的值,而这个新值没有及时写回主内存中,那么其他线程可能就看不到这个修改。volatile关键字确保每次读取变量都从主内存中进行,每次修改变量后都会立即写回主内存,从而保证了变量修改的可见性。

2. 禁止指令重排序

在Java内存模型中,编译器和处理器可能会对指令进行重排序,以提高程序的执行效率。但是,这种重排序可能会破坏多线程程序的正确性。当变量被声明为volatile后,会向编译器和处理器发出一个信号,告诉它们对这个变量相关的读写操作不允许进行重排序。volatile变量的写操作总是发生在读操作之前(或之后,具体取决于内存模型的具体实现),这样可以保证在并发环境中按照程序员的意图执行。

使用场景

volatile关键字适用于满足以下条件的场景:

  • 变量不依赖于当前值,或者能够确保只有单个线程更新变量的值。
  • 变量状态的改变不需要与其他状态变量共同参与不变约束。

注意事项

  • volatile不保证原子性。对volatile变量的操作(特别是复合操作,如volatileVar++)不是原子性的。如果需要原子性操作,应考虑使用java.util.concurrent.atomic包下的原子类。
  • volatile主要用于布尔标志或整数状态标志等简单状态的同步和通信,不适用于复杂状态的同步控制。

总的来说,volatile关键字是Java并发编程中保证共享变量在多线程间可见性的一种轻量级方式,但它的使用需要谨慎,确保在适当的场景下才使用。

2.既然 volatile 能够保证线程间的变量可见性,是不是就意味着基于 volatile 变量的运算就是并发安全的?

虽然volatile关键字确实能够保证变量在多个线程间的可见性,但它并不保证基于volatile变量的运算是并发安全的。并发安全不仅仅关乎于可见性,还涉及到操作的原子性和有序性。

原子性

原子性是指一个操作是不可中断的,即使是在多线程同时执行的情况下,一个操作要么完全执行,要么完全不执行,不会停留在中间某个步骤。对于volatile变量的单独读写操作是原子性的(例如,读取、赋值),但复合操作(如递增volatileVar++,或者volatileVar = volatileVar + 1)不是原子性的。复合操作包括多步骤:读取变量的当前值、计算新值、写入新值。在这些步骤之间,其他线程可能会修改这个变量的值,导致出现竞争条件。

示例

考虑下面的示例,其中count被声明为volatile变量:

public class Counter {private volatile int count = 0;public void increment() {count++;  // 这不是一个并发安全的操作}
}

虽然countvolatile的,但increment()方法中的count++操作包含读取count的当前值、增加1、写入新值三个步骤。如果多个线程同时执行increment()方法,就可能导致一些增加操作被覆盖,从而导致错误的结果。

解决办法

要使基于volatile变量的运算并发安全,可以采用以下方法之一:

  • 使用synchronized关键字同步方法或代码块,确保每次只有一个线程可以执行复合操作。
  • 使用java.util.concurrent.atomic包中提供的原子类(如AtomicInteger),这些类为多线程环境下的复合操作提供了原子性保证。

结论

volatile变量确保了变量更新后的可见性,但对于复合操作,仅仅使用volatile是不足以保证并发安全的。需要结合使用同步控制机制(如synchronized或原子类)来确保操作的原子性,进而实现并发安全。

3.ThreadLocal 是什么?有哪些使用场景?

ThreadLocal是Java提供的一个线程局部变量工具类,允许创建的变量只被同一个线程读写。换句话说,如果你在代码中创建了一个ThreadLocal变量,那么访问这个变量的每个线程都有自己独立初始化的变量副本,各个线程可以独立地改变自己的副本而不会影响到其他线程中的副本。

工作原理

ThreadLocal通过提供线程局部变量的副本,而不是所有线程共享一个变量,从而避免了线程之间的数据冲突。每个线程访问一个ThreadLocal变量时,实际上访问的是线程自己的局部变量。

使用场景

ThreadLocal适用于以下几种场景:

  1. 用户会话管理:在Web应用中,可以使用ThreadLocal来保存用户登录信息等,确保每个线程(通常对应一个用户会话)可以独立管理和访问自己的用户信息。
  2. 数据库连接管理:在多线程环境下管理数据库连接时,ThreadLocal可以确保每个线程拥有自己的数据库连接,避免多线程之间的数据库连接冲突。
  3. 事务管理:确保在同一线程内执行的所有数据库操作都在同一事务上下文中。
  4. 避免传递大量参数:当需要在多个方法之间传递相同的参数(尤其是当这些参数不应该被外部访问时),可以考虑使用ThreadLocal来避免这些参数的传递。
  5. 性能优化:在需要高性能的应用中,使用ThreadLocal可以减少同步的需求,因为每个线程访问的是自己独立的变量。

示例代码

使用ThreadLocal存储线程特定的数据:

public class ThreadLocalExample {// 创建一个ThreadLocal变量private static final ThreadLocal<Integer> threadLocalValue = ThreadLocal.withInitial(() -> 1);public static void main(String[] args) {// 线程1new Thread(() -> {threadLocalValue.set(100);System.out.println(Thread.currentThread().getName() + ": " + threadLocalValue.get());}, "Thread A").start();// 线程2new Thread(() -> {threadLocalValue.set(200);System.out.println(Thread.currentThread().getName() + ": " + threadLocalValue.get());// 移除当前线程的threadLocalValue值threadLocalValue.remove();}, "Thread B").start();}
}

注意事项

虽然ThreadLocal非常有用,但使用不当可能会导致内存泄露。因为ThreadLocal变量的生命周期是跟线程一样长的,如果线程不终止,那么这些ThreadLocal变量会一直存在,甚至可能导致其所引用的对象无法被垃圾回收。为了避免这种情况,建议在不再需要存储在ThreadLocal变量中的数据时调用ThreadLocal.remove()方法来清理资源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/760475.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GEE高阶案例——Landsat/Sentinel/MODIS影像进行缨帽变换一行代码实现

本教程的主要目的是利用eemont中的tasseledCap()的函数进行缨帽变换实现。 在 eemont 中,可使用扩展到 ee.Image 和 ee.ImageCollection 对象的 tasseledCap 方法计算缨帽亮度、绿度和湿度组件。只需从支持的平台加载图像,然后使用 tasseledCap 添加分量带即可。 代码: !p…

H6603实地架构降压芯片100V耐压 80V 72V 60V 48V单片机/模块供电应用

H6603 是一款内置功率 MOSFET降压开关转换器。在宽输入范围内&#xff0c;其最大持续输出电流 0.8A&#xff0c;具有极好的负载和线性调整率。电流控制模式提供了快速瞬态响应&#xff0c;并使环路更易稳定。故障保护包括逐周期限流保护和过温保护。H6603 最大限度地减少了现有…

智能驾驶域控制器行业介绍

汽车智能驾驶功能持续高速渗透&#xff0c;带来智能驾驶域控制器市场空间快速增 长。智驾域控制器是智能驾驶决策环节的重要零部件&#xff0c;主要功能为处理感知 信息、进行规划决策等。其核心部件主要为计算芯片&#xff0c;英伟达、地平线等芯 片厂商市场地位突出。随着消费…

ECharts5 应用篇

跨平台方案 服务端渲染 服务端 SVG 渲染 5.3.0 里新引入了零依赖的服务端 SVG 字符串渲染方案&#xff1a; // 服务端代码 const echarts require(echarts);// 在 SSR 模式下第一个参数不需要再传入 DOM 对象 let chart echarts.init(null, null, {renderer: svg, // 必须使用…

(C语言) print输出函数系列介绍

(C语言) print输出函数系列介绍 文章目录 (C语言) print输出函数系列介绍前言输出系列函数&#x1f5a8;️printf&#x1f5a8;️sprintf & snprintf&#x1f5a8;️fprintf&#x1f5a8;️vprintf&#x1f5a8;️dprintf&#x1f5a8;️puts&#x1f5a8;️fputs&#x1f…

Spring6--IOC反转控制 / 基于XML管理bean

1. 容器IOC 先理解概念&#xff0c;再进行实际操作。概念比较偏术语化&#xff0c;第一次看可能看不懂&#xff0c;建议多看几遍&#xff0c;再尝试自己独立复述一遍&#xff0c;效果会好些 1.1. IOC容器 1.1.1. 控制反转&#xff08;IOC&#xff09; IOC (Inversion of Con…

AL379芯片和AL383芯片是一款DC-DC升压芯片IC

首先&#xff0c;我们来了解HU6283芯片5V升压12V芯片的工作原理。这种芯片通常采用开关电源技术&#xff0c;通过高频开关控制&#xff0c;将5V的输入电压转换为12V的输出电压。开关电源技术具有高效、稳定、体积小等优点&#xff0c;因此在电子设备中得到了广泛应用。5V升压12…

各种小功能

目录 Python在指定目录创建多个相似命名的文件夹 Python 在指定目录创建多个相似命名的文件夹

Python 使用requests模块 执行Web API调用 获取网站数据并可视化

import requests#执行web api调用&#xff0c;并将响应存储在response_dict字典中 urlhttps://api.github.com/search/repositories?qlanguage:python&sortstars headers{Accept:application/vnd.github.v3json} rrequests.get(url,headersheaders) print(fStatus code:{r…

软件测评中心分享:软件鉴定测试与验收测试有什么联系和区别?

1、软件鉴定测试   软件鉴定测试是在软件开发完成后进行的一个核心环节&#xff0c;是通过对软件进行功能性、性能、安全性等方面的综合测试&#xff0c;来验证软件是否符合规定的需求和标准。 2、软件验收测试   软件验收测试是软件开发工作结束后的最后一个环节&#xf…

并发编程所需的底层基础

一、计算机运行的底层原理 1.多级层次的存储结构 ①:辅存 固态盘不是主要的应用对象&#xff0c;因为固态盘的使用次数是有限的&#xff0c;无法支撑高并发场景 磁盘存储的最基本原理是电生磁。 磁盘的磁道里边有很多的磁颗粒&#xff0c;磁颗粒上边有一层薄膜为了防止磁点氧…

MySQL连接池和MySQL永久连接(长连接)在数据库连接管理方面都有其独特的优缺点。swoole pdopool实现

MySQL连接池的优点&#xff1a; 资源重用&#xff1a;连接池中的连接可以被多个请求共享&#xff0c;避免了频繁创建和释放连接所引起的大量性能开销。这有助于减少内存碎片以及数据库临时进程或线程的数量&#xff0c;从而增进系统运行环境的平稳性。更快的系统响应速度&…

5G网络架构与组网部署03--5G网络组网部署

1. SA组网与NSA组网 &#xff08;1&#xff09;NSA 非独立组网&#xff1a;终端同时接入4G基站和5G基站&#xff0c;只能实现5G部分功能 &#xff08;2&#xff09;SA组网【最终目标】&#xff1a;5G基站可以单独提供服务&#xff0c;接入的是5G核心网 区别&#xff1a;同一时间…

01-java面试题八股文-----java基础——20题

文章目录 <font color"red">1、java语言有哪些特点&#xff1a;<font color"red">2、面向对象和面向过程的区别<font color"red">3、标识符的命名规则。<font color"red">4、八种基本数据类型的大小&#xff…

Linux常用端口解释

著名端口 端口号码 / 层名称注释1tcpmuxTCP 端口服务多路复用5rje远程作业入口7echoEcho 服务9discard用于连接测试的空服务11systat用于列举连接了的端口的系统状态13daytime给请求主机发送日期和时间17qotd给连接了的主机发送每日格言18msp消息发送协议19chargen字符生成服务…

STM32CubeMX+freeRTOS+事件组 多任务处理LED和串口打印

摘要:利用CubeMx配置freeeRTOS建立任务并使用事件组实现按键按下时 LED开关和打印信息到串口,上位机接收显示。 验证STM32CubeMx配置的FreeRTOS的任务和事件组使用 方案:按下Key1,绿灯亮或者灭,同时串口打印Key1被按下了到上位机;相关端口和串口配置省略。 新建三个任务…

[mailto:steloj@mailfence.com].steloj勒索病毒数据怎么处理|数据解密恢复

导言&#xff1a; 随着互联网的普及和数字化进程的加速&#xff0c;网络安全已成为人们关注的焦点。近年来&#xff0c;勒索病毒以其高隐蔽性和破坏性在互联网上大肆传播&#xff0c;给个人和企业带来了巨大的损失。其中&#xff0c;[mailto:stelojmailfence.com].steloj勒索病…

Sora底层技术原理:Stable Diffusion运行原理

AIGC 热潮正猛烈地席卷开来&#xff0c;可以说 Stable Diffusion 开源发布把 AI 图像生成提高了全新高度&#xff0c;特别是 ControlNet 和 T2I-Adapter 控制模块的提出进一步提高生成可控性&#xff0c;也在逐渐改变一部分行业的生产模式。惊艳其出色表现&#xff0c;也不禁好…

嵌入式开发--获取STM32产品系列的信息

嵌入式开发–获取STM32产品系列和容量信息 获取STM32产品系列 有时候我们需要知道当前MCU是STM32的哪一个系列&#xff0c;这当然可以从外部丝印看出来&#xff0c;但是运行在内部的软件如何知道呢&#xff1f; ST为我们提供了一个接口&#xff0c;对于STM32的所有MCU&#x…

xshell链接不上hadoop虚拟机

输入ifconfig查看是否有ens33 没有的话解决方案如下&#xff1a; systemctl stop NetworkManager systemctl restart network.service service network restartsys 依次输入以上命令 如果报错或者没用的话&#xff0c;进入root重新输入一遍这三个命令 大功告成&#xff01;…