Java并发编程常识 (下)

简介: Java并发编程常识 (下)

缓冲行对齐,这个应该是一个需要掌握的知识点,属于关于程序优化的奇技淫巧。

偶现于面试环节。

对齐的目的是为了解决伪共享(False Sharing)的发生。

不知道伪共享的朋友,建议去了解一下。

PPT 中的例子的源码来源是:

com.google.code.yanf4j.util.LinkedTransferQueue.PaddedAtomicReference


image.png

需要注意的是,在 Java8 里面,提供了更加优雅的解决方案:@Contented 注解。

image.png

image.png

这个也是一个非常经典的、关于单例模式的演变过程。

PPT 上一共四个单例模式的写法,我们一个个的看。

image.png

这就是我们耳熟能详的饿汉式单例。通过提前初始化的方式,解决了并发问题,保证了单例性。

这里面最关键的就是 final static 关键字。

作者也用了蓝色做以区分,肯定是有深意的。

来,一起背一遍类的加载过程:

加载、验证、准备、解析、初始化。

比如下面这个例子:

public static int value =123

变量 value,只有 static 修饰,那么该变量在准备阶段被赋上初始值,即 0。

在初始化阶段被赋上 123。

但是当再多一个 final 修饰的时候:

public final static int value =123

value 变量在准备阶段就会被赋上 123。

所以,你想想上面的饿汉式,是不是一个道理?

而这一方面的知识点,在《深入理解Java虚拟机》一书里面,写的还是很清楚的。

但是饿汉式有一个明显的劣势,那就是不管应用程序是否使用,都会被初始化出来。

这样并不优雅。

于是,就到了第二段程序,饱汉式。


image.png

在需要使用的时候,才进行初始化操作。

但是怎么保证线程安全呢?

通过在方法上加 synchronized 关键字的方式来保证了线程安全?

但是这个玩意真的安全吗?

这可能是面试官最喜欢问的问题之一吧。

要是你之前不知道,也许打死你也想不到还有拿到一个只初始化了一半的对象的情况。

简单来说就是 new Singleton() 不是原子性的,所以会导致 if 条件满足时,instance 并没有完全初始化。

于是就引出了下面这段程序:

image.png

传说中的双重检查加锁。

而这段程序最容易被“忽视”的就是 volatile 关键字了。

如果没有 volatile 关键字,那么这个程序也是废的。

还有,需要注意的是梁飞在这里备注了一个 jdk1.5+

为什么呢?

其实答案就写在《Java并发编程实战》的第 287 页:

image.png

在这本书里面,形容双重检查加锁的成语是:声名狼藉。

而且在图片里面可以看到:促使该模式出现的驱动力已经不复存在,并不是一种高效的优化措施。

现在,我觉得双重检查加锁主要还是应用在面试环节。

明明就不是一种高效的优化措施,却还是一个高频考点,为什么呢?

还不是八股文害人啊。

接下来说最后一种,也是作者推崇的方式:

image.png

这个骚操作的学名叫做“基于类初始化的单例模式解决方案”。

JVM 在 Class 被加载后,且被线程使用之前,也就是类的初始化阶段,会去获取一个锁。

这个锁可以保证多个线程对同一个类进行初始化时,只有一个线程能初始化成功。

而该方法的原理在《Java并发编程的艺术》一书的 3.8.4 章节解释的非常清楚。

什么?这两本书你都没有?

赶紧去搞一本吧,写的还是挺好的,我以前多次推荐过。

image.png

额......

这页我也没看明白。

我觉得肯定是有一个上下文的,只是梁飞没有写在 PPT 里面。

导致我看的云里雾里的。


image.png

image.png

这里只写到了 CountDownLatch 和 CyclicBarrier 。

其实还有一个很重要的、很常用的、工具类:Semaphore。

如果不知道,可以看看这篇文章:

我靠!Semaphore里面居然有这么一个大坑!

如果你上面三个都不知道。

赶!紧!去!学!

image.png

image.png

image.png

image.png

打印出来,贴在电脑旁边,朗读并背诵本页。


最后说一句



文中提到的两个 PPT 和一个文件:

  • 阿里巴巴(B2B)的服务框架探索.ppt
  • Java并发编程常识.ppt
  • hsdis-amd64.dll

关注公众号【why技术】,然后在后台回复关键字【ppt】即可获得。

才疏学浅,难免会有纰漏,如果你发现了错误的地方,可以在后台提出来,我对其加以修改。 感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。

我是 why,一个主要写代码,经常写文章,偶尔拍视频的程序猿。


目录
相关文章
|
2月前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
1月前
|
安全 Java 程序员
深入理解Java内存模型与并发编程####
本文旨在探讨Java内存模型(JMM)的复杂性及其对并发编程的影响,不同于传统的摘要形式,本文将以一个实际案例为引子,逐步揭示JMM的核心概念,包括原子性、可见性、有序性,以及这些特性在多线程环境下的具体表现。通过对比分析不同并发工具类的应用,如synchronized、volatile关键字、Lock接口及其实现等,本文将展示如何在实践中有效利用JMM来设计高效且安全的并发程序。最后,还将简要介绍Java 8及更高版本中引入的新特性,如StampedLock,以及它们如何进一步优化多线程编程模型。 ####
34 0
|
1月前
|
Java 程序员
Java编程中的异常处理:从基础到高级
在Java的世界中,异常处理是代码健壮性的守护神。本文将带你从异常的基本概念出发,逐步深入到高级用法,探索如何优雅地处理程序中的错误和异常情况。通过实际案例,我们将一起学习如何编写更可靠、更易于维护的Java代码。准备好了吗?让我们一起踏上这段旅程,解锁Java异常处理的秘密!
|
17天前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
Java 并发编程——volatile 关键字解析
|
21天前
|
算法 Java 调度
java并发编程中Monitor里的waitSet和EntryList都是做什么的
在Java并发编程中,Monitor内部包含两个重要队列:等待集(Wait Set)和入口列表(Entry List)。Wait Set用于线程的条件等待和协作,线程调用`wait()`后进入此集合,通过`notify()`或`notifyAll()`唤醒。Entry List则管理锁的竞争,未能获取锁的线程在此排队,等待锁释放后重新竞争。理解两者区别有助于设计高效的多线程程序。 - **Wait Set**:线程调用`wait()`后进入,等待条件满足被唤醒,需重新竞争锁。 - **Entry List**:多个线程竞争锁时,未获锁的线程在此排队,等待锁释放后获取锁继续执行。
61 12
|
18天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
102 2
|
2月前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
2月前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
1月前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
1月前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
53 3