当前位置: 首页 > news >正文

JVM-默背版

1.JVM对sychronized的优化:锁膨胀、锁消除、锁粗化、自适应自旋锁
(1)锁膨胀:从无锁、偏向锁、轻量级锁、重量级锁的过程叫做锁膨胀。在JDK1.6以前,sychronized是由重量级锁实现的,加锁和解锁的过程需要从用户态切换到内核态,性能低下。有了锁膨胀机制,大多数场景可以使用无锁、偏向锁和轻量级锁,在执行并发操作的时候,避免了线程从用户态到内核态,从而减少性能的开销。
(2)锁消除:JVM检测到代码段不再被共享和竞争,此时就会取消该代码段的所属的代码段。
(3)锁粗化:将多个连续的加锁、解锁操作链接在一起,形成一个范围更大的锁。
(4)自适应自旋锁:通过自身循环,获取锁的一种方式,避免了线程开启和线程挂起的性能开销。因为线程开启和线程挂起需要从用户态转到内核态,这个过程是比较缓慢的,性能比较低下。
2.介绍AQS
3.CAS和AQS的关系
4.用AQS实现可重入的公平锁
5.ThreadLocal的作用
6.乐观锁和悲观锁
7.java中实现乐观锁的方式
8.CAS的缺点
9.为什么不能所有的锁都用CAS
10.CAS有什么问题,java是如何解决的

11.volatile的作用
volatile可以保证可见性,不能保证原子性,所以会引发线程安全的问题。如果一个线程修改了使用volatile关键字的修饰的变量,其他线程也能获取到这个变量的最新值,从而避免了数据不一致的状态。
对于复合操作,比如i++这种自增操作,因为不是原子操作,如果有多个线程修改了i的值,volatile是不能保证线程安全的。需要用Sychronized和Lock来保证原子性和线程安全。

12.volatile和sychronized的比较

13.什么是公平锁和非公平锁。

14.非公平锁的吞吐量为什么比公平锁大。
15.reentrantlock是怎么实现公平锁的。
公平锁和非公平锁的区别是,公平锁中有hasQueueProcessors()=false方法,来看自己之前还有线程在排队吗
hasQueuedPredecessors() 用来判断 当前等待队列是否有线程在排队获取锁。对于非公平锁,无论是否已经有线程在排队,都会尝试获取锁,获取不到再排队。
tryLock()方法是非公平的,可以插队
16.线程池的核心参数
new SynchronousQueue<>() 是 Java 并发包 里的一个用法。SynchronousQueue 是 java.util.concurrent 提供的一种特殊的 阻塞队列。

和普通的队列(ArrayBlockingQueue、LinkedBlockingQueue)不同:它不存储任何元素,容量是 0。

每次 put() 必须等到有另一个线程 take(),才能成功;反过来 take() 也必须等到有人 put()。

所以它其实是一个 线程之间直接移交(handoff)数据的工具。
把 SynchronousQueue 想象成 过手交易:

线程 A 想交给线程 B 一个包裹。

A 必须等到 B 伸手来拿(调用 take()),才能把东西放出去。

它不像普通队列能“先存进去,等别人慢慢取”。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
17.await()方法
(1)Condition.await()
在 java.util.concurrent.locks.Condition 接口中,await() 是用来 让当前线程等待,直到其他线程通过 signal() 或 signalAll() 唤醒它。常用场景是自定义锁下的线程等待/通知机制。

import java.util.concurrent.locks.*;public class AwaitExample {private static final Lock lock = new ReentrantLock();private static final Condition condition = lock.newCondition();public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {lock.lock();try {System.out.println("Thread t1: Waiting...");condition.await(); // 等待被唤醒System.out.println("Thread t1: Woke up!");} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}});Thread t2 = new Thread(() -> {lock.lock();try {System.out.println("Thread t2: Sleeping for 2s...");Thread.sleep(2000);condition.signal(); // 唤醒等待的线程System.out.println("Thread t2: Sent signal!");} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}});t1.start();t2.start();t1.join();t2.join();}
}

await() 会释放锁并让当前线程等待。

signal() 或 signalAll() 会唤醒等待线程。

与 Object.wait() 类似,但更灵活,可以在 Lock 中使用。
(2)CountDownLatch.await()
在 java.util.concurrent.CountDownLatch 中,await() 是 阻塞当前线程,直到计数器为 0。

CountDownLatch latch = new CountDownLatch(3);for (int i = 0; i < 3; i++) {new Thread(() -> {System.out.println(Thread.currentThread().getName() + " finished work");latch.countDown(); // 计数器减 1}).start();
}latch.await(); // 阻塞,直到计数器为 0
System.out.println("All threads finished!");

(3)CompletableFuture.await()(类似概念) 不常用
在 异步编程里,比如在某些库或 Kotlin/JavaScript 的 async/await 中,await 用来 等待异步操作完成并获取结果。Java 标准库里 CompletableFuture 没有 await() 方法,但可以用 get() 或 join() 实现类似效果。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");
String result = future.join(); // 等待结果
System.out.println(result); // 输出 "Hello"

18.例子3

join() → 一直等,直到目标线程结束。
前面例子里写的 t1.join(); t2.join(); 的意思就是:
主线程会先等待 t1 执行结束,再等待 t2 执行结束,最后才继续往下走。这样可以确保两个子线程都跑完。
假设两个线程并发读写同一个整型变量,初始值为零,每个线程加 50次,结果可能是什么?
在没有任何同步机制的情况下,两个线程并发对同一个整型变量进行 50 次加1操作,最终结果可能是100,也可能小于 100,最坏的结果是 50,也就是最终的结果可能是在 [50,100]。
小于 100 情况的分析,由于对整型变量的 num++ 操作不是原子操作,它实际上包含了三个步骤:读取变量的值、将值加 1、将新值写回变量。在多线程环境下,可能会出现线程安全问题。例如,线程1和线程2同时读取了变量的当前值,然后各自将其加 1,最后都将相同的新值写回变量,这就导致了一次加 1操作的丢失。这种情况会多次发生,最终结果就会小于 100。

import java.util.concurrent.atomic.AtomicInteger;public class AtomicIntegerAddition {private static AtomicInteger num = new AtomicInteger(0);public static void main(String[] args) throws InterruptedException{Thread thread1 = new Thread(()->{for(int i=0;i<50;i++){num.incrementAndGet();}});Thread thread2 = new Thread(()-> {for(int i=0;i<50;i++){num.incrementAndGet();}});thread1.start();thread2.start();thread1.join();thread2.join();System.out.println("最终结果:"+ num.get());}}

通过sychronized方法,保证操作的互斥性。

public class SynchronizedAddition {private static int num =0;private static final Object lock = new Object();public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(()-> {for(int i=0;i<50;i++){synchronized(lock){num++;}}});Thread thread2 = new Thread(()-> {for (int i = 0; i < 50; i++) {synchronized (lock) {num++;}}});thread1.start();thread2.start();thread1.join();thread2.join();System.out.println("最终结果:"+ num);}}
http://www.xdnf.cn/news/1486441.html

相关文章:

  • 实验室服务器配置|通过Docker实现Linux系统多用户隔离与安全防控
  • Flink NetworkBufferPool核心原理解析
  • Android --- SystemUI 导入Android Studio及debug
  • 2025年体制内职业发展相关认证选择指南
  • 超越自动补全:将AI编码助手深度集成到你的开发工作流​​
  • 微信小程序中实现AI对话、生成3D图像并使用xr-frame演示
  • C++ 连接 Redis:redis-plus-plus 安装与使用入门指南
  • 关于npm的钩子函数
  • 【iOS】push,pop和present,dismiss
  • 上架商品合规流程有多条,有的长,有的短,有的需要审核,校验商品的合规性
  • RestTemplate使用 | RestTemplate设置http连接池参数
  • axios的两种异步方式对比
  • K8S-Pod(下)
  • 笔记本、平板如何成为电脑拓展屏?向日葵16成为副屏功能一键实现
  • python---静态方法和类方法
  • Python学习——安装配置python环境+入门
  • Onecode 可视化动作揭秘系列二:组件类型个性化配置技术协议
  • 嵌入式解谜日志之数据结构—基本概念
  • 插入排序与希尔排序
  • Python3使用Flask开发Web项目新手入门开发文档
  • JavaEE 进阶第三期:开启前端入门之旅(三)
  • 数据结构——排序
  • 内网后渗透攻击--linux系统(权限维持)
  • MySQL 8.0+ 内核剖析:架构、事务与数据管理
  • thinkphp和vue基于Workerman搭建Websocket服务实现用户实时聊天,完整前后端源码demo及数据表sql
  • 20250907_梳理异地备份每日自动巡检py脚本逻辑流程+安装Python+PyCharm+配置自动运行
  • 什么叫进件?在第三方支付行业里,这是一个非常专业的词汇。
  • Linux驱动开发(1)环境与代码框架
  • Linux —— 虚拟进程地址空间
  • Java-Spring入门指南(三)深入剖析IoC容器与Bean核心机制