Java并发编程的艺术[3]

举报
赵KK日常技术记录 发表于 2023/06/29 21:42:43 2023/06/29
【摘要】 锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(但是有些锁可以允许多个线程并发的访问共享资源,比如读写锁)。参考《Java并发编程的艺术》happens-before简介从JDK 5开始,Java使用新的JSR-133内存模型(除非特别说明,本文针对的都是JSR-133内存模型)。JSR-133使用happens-before的概念来阐述操作之间的内...

锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(但是有些锁可以允许多个线程并发的访问共享资源,比如读写锁)。

参考《Java并发编程的艺术》

happens-before简介

从JDK 5开始,Java使用新的JSR-133内存模型(除非特别说明,本文针对的都是JSR-133内存模型)。JSR-133使用happens-before的概念来阐述操作之间的内存可见性。在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在happens-before关系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间

图片


·程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。

·监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。

·volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。

·传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。

注意 两个操作之间具有happens-before关系,并不意味着前一个操作必须要在后一个操作之前执行!happens-before仅仅要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前(the first is visible to and ordered before the second)。

3.2 重排序

重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。

3.2.1 数据依赖性

如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间

就存在数据依赖性

as-if-serial语义

as-if-serial语义的意思是:不管怎么重排序(编译器和处理器为了提高并行度),(单线程)

程序的执行结果不能被改变

顺序一致性内存模型

图片


其实就是线程所见都是单一的执行顺序,i++就是编译指令为4步的非原子操作,执行顺序可变


数据通过总线在处理器和内存之间传递。每次处理器和内存之间的数据传递都是通过一系列步骤来完成的,这一系列步骤称之为总线事务(Bus Transaction)。

图片


疑问?这个总线与CPU的总线是一个概念吗?宏观的作用上差不多

图片

如图  来自B站柏義

volatile禁止指令重排是因为LoadStore导致的不能重排

图片


对公平锁和非公平锁的内存语义做个总结。

·公平锁和非公平锁释放时,最后都要写一个volatile变量state。

·公平锁获取时,首先会去读volatile变量。

·非公平锁获取时,首先会用CAS更新volatile变量,这个操作同时具有volatile读和volatile写的内存语义。

线程的优先级

Deamon线程(美[ˈdiːmən])

Daemon线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。这意味着,当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出。可以通过调用Thread.setDaemon(true)将线程设置为Daemon线程。

1.当主线程退出时,守候子线程会执行完毕吗?

不一定执行

ti.setDaemon(true);

守候线程执行依赖于执行时间

理解中断

Thread.interrupt()   设置状态

isInterrupted()    判断 返回Boolean

interrupted 即判断又清除

中断可以理解为线程的一个标识位属性,它表示一个运行中的线程是否被其他线程进行了中断操作。中断好比其他线程对该线程打了个招呼,其他线程通过调用该线程的interrupt()方法对其进行中断操作。

线程通过检查自身是否被中断来进行响应,线程通过方法isInterrupted()来进行判断是否被中断,也可以调用静态方法Thread.interrupted()对当前线程的中断标识位进行复位.

线程池技术及其实例

ThreadPoolExecutor源码

// 执行一个Job,这个Job需要实现Runnablepublic void execute(Runnable command) {} // 关闭线程池public void shutdown() {}处理正在等待的任务,并返回任务列表public List<Runnable> shutdownNow() {}//1)菜用循环CAS操作来将线程数加1;2)新建一个线程并启用。private boolean addWorker(Runnable firstTask, boolean core) {}//获取线程池数量public int getPoolSize() {}


图片

总的来说还是看源码吧,多看,多参考资料,通过原理,源码,操作系统等资料熟悉JUC,大多数的资料总结的都是一样的。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。