java多线程初探

devtools/2024/12/23 7:00:29/

文章目录

  • countDownLatch
  • volatile
  • CAS
  • jdk1.6对synchronized的优化
    • 自旋锁
    • 锁消除
    • 锁粗化
    • 轻量级锁
    • 偏向锁
  • java AtomicBoolean compareAndSet Demo
  • threadlocal
  • concurrent queue
  • 原子操作是否需要同步
  • copyonwrite容器
  • 可重入锁
  • 公平与非公平
  • 并发编程步骤

countDownLatch

此类位于java.util.concurrent.countDownLatch。latch是门闩的意思。
有位博主打了个比方,在此引用:“三二一,芝麻开门”。
跟信号量的思想相似,不过countDownLatch更加简单。只有两个方法,一个是countDown,一个是await。countDown方法的效果就是倒数,await的作用是等待倒数至0。
一个背景是,即使各线程的工作量划分非常合理,它们也总会先后完成。
配合使用的效果是,确保数个协作的并发线程都完成后,才继续向下执行。

volatile

volatile的本意是易变的。一个背景是,易变的东西是不适合缓存的。
在C中,volatile的作用是,确保读写都访问变量地址(而不是缓存)。
在Java中也是同样的意思。
同步会让主存刷新。所以如果一个变量完全由 synchronized 的方法或代码
段 (或者 java.util.concurrent.atomic 库里类型之一) 所保护,则不需要让变量用volatile。
volatile关键字可以阻止重排 volatile变量周围的读写指令。这种重排规则称为 happens before 担保原则。这项原则保证在 volatile 变量读写之前发生的指令先于它们的读写之前发生。同样,任何跟随 volatile 变量之后读写的操作都保证发生在它们的读写之后。
bruce建议不要用这个关键字,用atomic系列来替代。

CAS

全称是compare and swap。已经得到汇编指令支持。
回想一下那道经典题,两个线程各执行100次自增,有哪些可能的结果。
1.线程a和b一开始都读到0,存在线程内存中;
2.线程a执行99次,将99写入主存;
3.线程b执行1次,将1写入主存;
4.线程a读到1;
5.线程b执行99次,将99写入主存;
6.线程a执行1次,将2写入主存。
其实,线程b在第三步的时候如果compare一下就会发现问题了。线程b在第一步读是0,在第三步读到的是99,这说明线程b在“读取-计算-准备写入”期间,有其它线程也在工作。
compare and swap就在于此,在写入之前,compare一下读到的值(99)和预期值(0),如果不同,就不写入,而是用读到的值重新计算。也就是重新进行“读取-计算-准备写入”的过程。
在这里插入图片描述
乐观,就是假设冲突较少,或者说“相信”多线程不会出问题。悲观,就是假设冲突较多。
因此,乐观锁适合并发量小,冲突确实比较少的场景;悲观锁则反之。

CAS和synchronized相比,好处在于,避免了线程状态的切换。
java中,Atomic开头的包装类,如AtomicInteger,底层实现就是CAS。相比synchronized,更加轻量。

jdk1.6对synchronized的优化

自旋锁

上文已经介绍。

锁消除

消除不可能存在数据竞争的锁

锁粗化

粗化的好处是不用加锁多次。

轻量级锁

无竞争条件时,通过CAS消除同步互斥

偏向锁

无竞争条件时,消除同步互斥,也不进行CAS操作。

java_AtomicBoolean_compareAndSet_Demo_48">java AtomicBoolean compareAndSet Demo

实现了一个计时器。

java">public class TimeController implements Runnable {private waitSeconds;public static AtomicBoolean isStop = new AtomicBoolean(false);//初始值public TimeController(long waitSeconds) {if(waitSeconds == 0) {waitSeconds = Long.MAX_VALUE;}}@Overridepublic void run() {while(waitSeconds > 0) {if(isStop.get() == true) {//提示信息break;}try {Thread.sleep(1000);} catch (InterruptedException e) {//提示信息}waitSeconds--;}isStop.compareAndSet(false, true);//第一个参数是expect,第二个参数是update}
}

threadlocal

相当于线程的私有存储空间,有get和set方法。
在这里插入图片描述

concurrent queue

据说java concurrent queue的size方法是O(n)的。还可深究。

原子操作是否需要同步

能通过Goetz测试的专家可以尝试用原子操作来代替同步。否则不要尝试。

可见性问题比原子性问题多得多。

原子操作并不解决可见性的问题。相反,同步机制强制多核处理器系统上的一个任务做出的修改必须在应用程序中是可见的。

对属性赋值,返回,通常是原子性的。
在Java中,自增不是原子性的。

copyonwrite容器

比如,CopyOnWriteArrayList。
多线程环境下保证线程安全(以免修改到一半被读取。只有在完成修改之后才可见), 并通过读写分离提高性能。
CopyOnWriteArraySet 使用 CopyOnWriteArrayList 来实现其无锁行为。
ConcurrentHashMap 和 ConcurrentLinkedQueue 使用类似的技术来允许并发读写,但是只复制和修改集合的一部分,而不是整个集合。

可重入锁

意思是,在一个线程中可以多次获取同一把锁。
比如:一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法,而无需重新获得锁。

公平与非公平

公平,先来的先获得锁。
非公平,谁抢到算谁的。
非公平的效率较高。synchronized是非公平的。
这两种情况一般一种是默认,另一种可以通过参数设置。

并发编程步骤

1.尽量别用。
2.尽量用stream.parallel和completableFutures。
3.不要共享变量,任务间的信息传递应该通过concurrent库中的并发数据结构。
4.共享变量时用atomic类,或者将所有对共享变量的访问加synchronized。
5.volatile和synchronized一般都可以避免,尽量用concurrent库组件来实现。


http://www.ppmy.cn/devtools/46308.html

相关文章

vscode导入自定义模块报错ModuleNotFoundError解决方案

问题描述 我的项目为great_gas_or_agents,目录结构如下: log_data_extract main.py math_algorithm 现在我运行main.py,报错:from math_algorithm.utils import parse_month_match_request,ModuleNotFoundError: No …

QT入门知识回顾

1 QT简介 1.1 Qt模块: Qt Core模块: 是QT类库的核心,所有其他模块都依赖这个模块 Qt Gui模块: 提供GUI程序的基本功能 Qt Network模块:提供跨平台的网络功能 Qt Widgets模块:提供创建用户界面的功能 1.2Qt的signal/slot机制 任何一个类只要类体前部书写 Q_OBJ…

Python开发入门:从基础到实践的全方位探索

Python开发入门:从基础到实践的全方位探索 在数字化浪潮席卷全球的今天,Python以其简洁、易读和强大的功能库,迅速成为了初学者和专业开发者们的首选语言。本文将带领读者走进Python的世界,从四个方面、五个方面、六个方面和七个…

github将默认分支main改为master

github将默认分支main改为master 1.进入github,点击setting 2.在setting中,选择Respositories,更新默认分支为master 3.选择要更新的项目,在项目中选择setting->general->切换默认分支

#centos7搭建php8+nginx环境#

场景:为了实现上传的pdf文件转成png图片,需要搭建一个php8nginx的运行环境,最后安装imagic扩展 安装顺序 php-> linux-> imagemagick -> ghostscript -> imagick 一:安装phpnginx环境 1、安装remi扩展源 remi源是Remi repository是包含最新…

404错误页面源码,简单实用的html错误页面模板

源码描述 小编精心准备一款404错误页面源码,简单实用的html错误页面模板,简单大气的页面布局,可以使用到不同的网站中,相信大家一定会喜欢的 效果预览 源码下载 https://www.qqmu.com/3375.html

只出现一次的数字II ---- 位运算

题目链接 题目: 分析: 对于只出现一次的数字, 他的任意一个bit位, 可能是0或1对于其余出现3次的数字, 假设有3n个数, 那么他们的任意一个bit相加的和可能是3n个0或3n个1那么对于数组中的全部数字的任意一个bit位之和共有三种情况: 3n个1 1 3n13n个0 1 13n个1 0 3n3n个0…

Java如何实现pdf转base64以及怎么反转?

问题需求 今天在做发送邮件功能的时候,发现邮件的附件部分,比如pdf文档,要求先把pdf转为base64,邮件才会发送。那接下来就先看看Java 如何把 pdf文档转为base64。 两种方式,一种是通过插件 jar 包的方式引入&#xf…