JavaGuide(3)

news/2024/12/21 22:48:01/

一、项目背景与简介

JavaGuide由GitHub用户Snailclimb开发并维护,是一个全面而深入的Java学习资源库。它旨在为Java初学者和有经验的开发者提供一个系统的学习路径和丰富的资源,帮助他们系统地学习和巩固Java及相关技术知识。

二、项目内容与特点

  1. Java基础:详细解释了Java的基本概念、语法和核心类库,为初学者打下坚实的基础。
  2. 集合框架:深入分析了ArrayList、LinkedList、HashMap等常用集合类的源码和使用场景,帮助开发者更好地理解和应用这些集合类。
  3. 并发编程:涵盖了线程、锁、并发集合等高级并发编程知识,帮助开发者掌握Java并发编程的核心技术。
  4. JVM:详细介绍了Java虚拟机的内存模型、垃圾回收机制和类加载过程,让开发者对Java的运行环境有更深入的了解。
  5. 新特性:总结了从Java 8到最新版本的各个版本的新特性,帮助开发者紧跟Java技术的最新发展。

此外,JavaGuide还涉及了计算机网络、操作系统、数据结构与算法等计算机科学基础知识,为开发者提供了一个全面的技术栈学习平台。

JavaGuide的特点还包括:

  • 全面性:覆盖了Java开发的各个方面,从基础到高级,从理论到实践,应有尽有。
  • 实用性:项目中的内容都是经过精心挑选和整理的,旨在解决实际开发中的常见问题。同时,提供了大量的代码示例和面试题,帮助开发者更好地理解和应用知识。
  • 更新及时:紧跟Java的最新发展,及时更新内容,确保信息的时效性和准确性。
  • 社区支持:JavaGuide是一个开源项目,拥有活跃的社区支持。用户可以在社区中参与贡献、寻求帮助或分享经验。

三、如何学习与使用JavaGuide

  1. 下载与安装:可以从JavaGuide的官方网站或GitHub仓库下载源代码压缩包,或者通过git命令来clone仓库。下载完成后,进入JavaGuide项目的根目录。
  2. 构建与运行:确保系统已经安装了Maven等构建工具,然后执行相应的命令来构建并运行JavaGuide。例如,可以使用“mvn clean package java -jar target/JavaGuide-xxx.jar”命令来运行JavaGuide。
  3. 学习与进阶:无论是Java初学者还是有一定经验的开发者,都可以通过JavaGuide系统地学习和巩固Java及相关技术知识。可以按照JavaGuide的学习路径逐步深入,也可以根据自己的兴趣和需求选择特定的章节进行学习。
  4. 面试准备:JavaGuide中包含了大量的面试题和解析,非常适合正在准备Java相关职位面试的求职者。可以通过学习这些面试题和解析来提高自己的面试技巧和竞争力。
  5. 日常开发参考:JavaGuide中的源码分析和最佳实践部分可以作为日常开发中的参考资料。在遇到问题时,可以查阅JavaGuide中的相关内容来寻找解决方案或灵感。

乐观锁和悲观锁详解

如果将悲观锁(Pessimistic Lock)和乐观锁(PessimisticLock 或 OptimisticLock)对应到现实生活中来。悲观锁有点像是一位比较悲观(也可以说是未雨绸缪)的人,总是会假设最坏的情况,避免出现问题。乐观锁有点像是一位比较乐观的人,总是会假设最好的情况,在要出现问题之前快速解决问题。

什么是悲观锁?

悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。也就是说,共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程

像 Java 中synchronizedReentrantLock等独占锁就是悲观锁思想的实现。

public void performSynchronisedTask() {synchronized (this) {// 需要同步的操作}
}private Lock lock = new ReentrantLock();
lock.lock();
try {// 需要同步的操作
} finally {lock.unlock();
}

高并发的场景下,激烈的锁竞争会造成线程阻塞,大量阻塞线程会导致系统的上下文切换,增加系统的性能开销。并且,悲观锁还可能会存在死锁问题(线程获得锁的顺序不当时),影响代码的正常运行。

什么是乐观锁?

乐观锁总是假设最好的情况,认为共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源(也就是数据)是否被其它线程修改了(具体方法可以使用版本号机制或 CAS 算法)。

在 Java 中java.util.concurrent.atomic包下面的原子变量类(比如AtomicIntegerLongAdder)就是使用了乐观锁的一种实现方式 CAS 实现的。

CAS 算法

CAS 的全称是 Compare And Swap(比较与交换) ,用于实现乐观锁,被广泛应用于各大框架中。CAS 的思想很简单,就是用一个预期值和要更新的变量值进行比较,两值相等才会进行更新。

CAS 是一个原子操作,底层依赖于一条 CPU 的原子指令。

原子操作 即最小不可拆分的操作,也就是说操作一旦开始,就不能被打断,直到操作完成。

CAS 涉及到三个操作数:

  • V:要更新的变量值(Var)
  • E:预期值(Expected)
  • N:拟写入的新值(New)

当且仅当 V 的值等于 E 时,CAS 通过原子方式用新值 N 来更新 V 的值。如果不等,说明已经有其它线程更新了 V,则当前线程放弃更新。

举一个简单的例子:线程 A 要修改变量 i 的值为 6,i 原值为 1(V = 1,E=1,N=6,假设不存在 ABA 问题)。

  1. i 与 1 进行比较,如果相等, 则说明没被其他线程修改,可以被设置为 6 。
  2. i 与 1 进行比较,如果不相等,则说明被其他线程修改,当前线程放弃更新,CAS 操作失败。

当多个线程同时使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败,但失败的线程并不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。

关于 CAS 的进一步介绍,可以阅读读者写的这篇文章:CAS 详解,其中详细提到了 Java 中 CAS 的实现以及 CAS 存在的一些问题。

一、JMM的基本概念

JMM定义了线程之间共享变量的可见性和有序性规则,为开发者提供了一种可靠的同步机制,以避免并发程序中常见的线程安全问题。JMM包含两个主要的内存区域:主内存和工作内存。

  1. 主内存:主内存是所有线程共享的内存区域,包含了程序的全局变量和静态变量。主内存是多个线程之间的交互媒介,线程之间通过主内存进行数据的传递和共享。
  2. 工作内存:工作内存是线程私有的内存区域,包含了线程栈中的局部变量和操作线程栈的操作数栈等。每个线程都有自己独立的工作内存,工作内存存储了线程在执行过程中需要用到的数据。

二、JMM的三大特性

JMM的三大特性是原子性、可见性和有序性,它们共同保证了多线程环境下数据的安全性和一致性。

  1. 原子性(Atomicity)

    • 原子性指的是一个操作要么全部执行成功,要么全部不执行。JMM保证了对基本类型的读写操作的原子性。例如,对一个int类型的变量进行++操作,JMM保证这个操作不会出现读取脏数据或者写入不完整数据的情况。
    • JMM通过使用synchronized关键字、volatile关键字和原子类(如AtomicInteger)等机制来保证原子性。
  2. 可见性(Visibility)

    • 可见性指的是一个线程对一个变量的写操作对其他线程可见。即使在不同的线程中,一个线程对共享变量的修改也能被其他线程立即观察到。
    • JMM通过使用锁机制和内存屏障来实现可见性。例如,使用synchronized关键字对代码块进行同步,每次进入同步块的线程都会从主内存中读取最新的值,保证了可见性。volatile关键字也可以确保被修饰的变量的写操作对其他线程立即可见。
  3. 有序性(Ordering)

    • 有序性指的是在一个线程中的操作顺序与程序代码的顺序一致。然而,在多线程环境下,由于指令重排和缓存一致性等原因,程序的执行顺序可能与代码顺序不一致。
    • JMM通过使用内存屏障来禁止特定类型的指令重排,保证程序的有序性。例如,volatile关键字可以禁止对volatile变量的读/写操作进行指令重排序。

三、JMM的Happens-Before规则

Happens-Before规则是JMM的核心原则之一,用于定义操作之间的顺序关系,基于此关系来保证数据的可见性和一致性。以下是Java中的Happens-Before规则:

  1. 程序顺序规则:在一个线程内,代码的执行顺序按照程序代码的书写顺序。
  2. 监视器锁规则:一个unlock操作在后续对同一锁的lock操作之前。
  3. volatile变量规则:对一个volatile变量的写操作先行发生于后面对该volatile变量的读操作。
  4. 线程启动规则:Thread.start()方法先行发生于此线程的每一个动作。
  5. 线程中断规则:对线程的interrupt()调用先行发生于被中断线程的代码检测到中断事件。
  6. 线程终止规则:线程的所有操作先行发生于此线程的终止检测(Thread.join()返回,Thread.isAlive()返回false)。
  7. 对象终结规则:对象的构造函数执行结束先行发生于finalize()方法的开始。

四、JMM的应用与注意事项

  1. 正确使用volatile关键字:当某个变量在多线程环境下被频繁读取且不需要复杂的同步操作时,可以使用volatile关键字来保证变量的可见性和有序性。
  2. 合理选择synchronized和Lock:在需要对共享资源进行原子操作且需要控制访问顺序时,可以使用synchronized关键字或Lock接口来保证原子性和可见性。
  3. 注意指令重排序的影响:编译器和处理器可能会对指令进行重排序以提高性能,但在多线程环境下,指令重排序可能导致内存可见性问题。因此,在编写多线程程序时,需要特别注意指令重排序的影响,并合理使用内存屏障等机制来保证程序的正确性。

http://www.ppmy.cn/news/1537217.html

相关文章

Linux / Steam deck 解压问题/解压失败

一般我们使用ark软件打开压缩包可能会显示“压缩包为空”或者“无法打开其内容”,但是放在Windows系统中又能正常解压 我们可以用命令行来正确解压 第一步,安装p7zip,过程中如果需要输入密码,正常盲输入,按回车即可 …

请描述一下数据库的负载测试和压力测试。请简要描述不同类型的联接(如内联接、左外联接、右外联接、全外联接等)。

请描述一下数据库的负载测试和压力测试。 一、数据库的负载测试 定义: 负载测试是通过模拟实际用户量和操作情况来评估数据库系统的性能和稳定性的过程。它主要通过逐步增加系统负载,测试系统性能的变化,并最终确定在满足性能指标的情况下&a…

CF2018C Tree Pruning 题解

Description 给定一棵有 n n n 个点的以 1 1 1 为根的树,在此问题中,叶子节点被定义为非根的度数为一的点。 每次操作可以删去一个叶子节点及其相连的边,你需要求出最小的操作次数,使得操作后所有叶子节点到根节点的距离相同。…

【数字图像处理】第一章 数字图像处理概论,图像的分类。主要内容

上理考研周导师的哔哩哔哩频道 我在频道里讲课哦 目录 1.1 图像处理的产生 1.2 图像的基本概念 图像的分类 图像的表示方法 1.3 数字图像处理系统 1.4 数字图像处理的应用与发展 一. 数字图像处理及其特点 2. 数字图像处理 二. 图像处理的主要内容 2. 数字图像处理…

红帽7—Mysql路由部署

MySQL Router 是一个对应用程序透明的InnoDB Cluster连接路由服务,提供负载均衡、应用连接故障转移和客户端路 由。 利用路由器的连接路由特性,用户可以编写应用程序来连接到路由器,并令路由器使用相应的路由策略 来处理连接,使其…

明星周边销售网站开发:SpringBoot技术全解析

1系统概述 1.1 研究背景 如今互联网高速发展,网络遍布全球,通过互联网发布的消息能快而方便的传播到世界每个角落,并且互联网上能传播的信息也很广,比如文字、图片、声音、视频等。从而,这种种好处使得互联网成了信息传…

面试知识储备-多线程

1.线程的概念 线程使得在一个程序中可以同时执行多个任务。在 Java 应用程序中,多个线程可以同时运行,例如一个线程可以处理用户输入,另一个线程可以进行后台数据处理。 2.创建线程的方式 (1)重写thread类中的run方法…

噪声分布 双峰,模拟函数 或者模拟方法 python人工智能 深度神经网络

在Python中模拟双峰分布,可以通过多种方法实现。以下是一些常用的方法: 1. **使用正态分布混合**: 可以通过组合两个正态分布来创建一个双峰分布。每个正态分布都有其自己的均值(mu)和标准差(sigma&…