并发编程(二)

  • 临界区·
  • 竞态条件
  • Synchronized对象锁
  • 变量的线程安全分析
  • Moniter
  • 轻量级锁
  • 自旋优化
  • 偏向优化
  • 批量重偏向
  • 批量撤销
  • 锁消除
  • wait/notify 原理
  • park/unpark
  • 死锁
  • 活锁
  • 饥饿
  • ReentrantLock

临界区·

一个代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区

竞态条件

多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件

Synchronized对象锁

语法
Synchronized(对象) {
临界区
}

锁在对象方法上锁的是this对象
锁在static方法上锁的是class对象

变量的线程安全分析

成员变量与静态变量是否线程安全?

  1. 如果它们没有被共享,则安全
  2. 如果它们被共享了,根据他们的状态能否改变,分为两种情况
    ○1如果只有读操作,安全
    ○2如果有读写操作,则这段代码是临界区,要考虑线程安全

局部变量是否线程安全?

  1. 局部变量是线程安全的
  2. 局部变量引用的对象未必
    ○1如果该对象没有逃离方法的作用访问,则安全
    ○2如果对象逃离方法的作用访问,需要考虑线程安全

常见线程安全类
String、Integer、StringBuffer、Random、Vector、Hashtable、 java.util.concurrent 包下的类

Moniter

1.当线程运行临界区中加锁的代码时,锁的对象会先与Moniter关联
2.刚开始Moniter中Owner为null
3.当Thread-2执行synchronized(obj)就会将Moniter的所有者Owner设为Thread-2.Moniter中只能有一个Owner
4.在Thread-2上锁过程中,如果Thread-3、Thread-4、Thread-5也来执行synchronized(obj),就会进入entrylist BLOCKED
5.Thread执行完同步代码块的内容,唤醒EntryList中等待的线程来竞争锁,竞争非公平

轻量级锁

如果一个对象虽然有多线程访问,但多线程访问时间是错开的,那么可以用轻量级锁来优化
Synchronized优先进行轻量级锁加锁,加锁失败则会用重量级锁

创建锁记录对象,每个线程的栈帧都会包含一个锁记录的结构,内部可以存储锁定对象的MarkWord

让锁记录中Object referernce指向对象,并尝试替换Object的MarkWord,将MarkWord的值储存入锁记录

如果替换成功,对象头中存储了锁记录地址和状态,表示由该线程给对象加锁

如果失败,有两种情况

  1. 如果是其它线程已经持有了该 Object 的轻量级锁,这时表明有竞争,进入锁膨胀过程
  2. 如果是自己执行了 synchronized 锁重入,那么再添加一条 Lock Record 作为重入的计数

    当退出 synchronized 代码块(解锁时)如果有取值为 null 的锁记录,表示有重入,这时重置锁记录,表示重入计数减一

    当退出synchronized 代码块(解锁时)锁记录的值不为null,这时使用 cas 将 Mark Word 的值恢复给对象头
    成功,则解锁成功
    失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程

锁膨胀
如果在尝试加轻量级锁过程中,操作无法成功,这时一种情况是其它线程为此对象加上了轻量级锁,这时要进行锁膨胀,将轻量级锁变为重量级锁

加锁失败,进入锁膨胀流程
为Object对象申请Moniter锁,让Object指向重量级锁,未能获得锁的线程进入Moniter的EntryList BLOCKED

自旋优化

重量级锁竞争失败,先进行自旋优化而不是直接进入BLOCKED,阻塞要进行上下文切换,耗费性能,自旋能减少上下文切换

偏向优化

轻量级锁在没有竞争时,每次重入仍要进行CAS操作
偏向锁第一次使用CAS时就将线程ID设置到对象头的MaekWord中,之后发现这个线程ID是自己的,就不会重新CAS,以后只要不发生竞争,这个对象就归该线程所有

对象头中偏向锁后三位为101
程序运行时偏向锁默认开启
调用hasjcode()会禁用掉偏向锁,因为hashcode会占31位,对象头中会替换掉偏向状态

批量重偏向

当将thread1的偏向锁重偏向为thread2次数到达阈值后(默认20),会进行批量重偏向

批量撤销

当撤销偏向锁阈值超过40次后,jvm会觉得偏向错了,不该偏向,于是整个类的所有对象都变为不可偏向,新建的对象也不可偏向

锁消除

//控制是否加锁消除优化
-XX:-EliminateLocks

wait/notify 原理

  1. owner线程发现条件不满足,调用wait方法,即可进入waitset变为waiting状态
  2. BLOCKED和WATING的线程都会处于阻塞状态,不占用CPU时间片
  3. BLOCKED线程会在owner线程释放锁时被唤醒
  4. WATING线程在owner线程调用notify或notifyall时唤醒,但唤醒后并不立即获得锁,仍需进入EntryList重新竞争

    wait会使线程进入waitset中等待
    必须获得了锁才能进入所属的waitset
    waitset中可以有多个线程等待)

sleep(long n)与wait(long n)区别

  1. Wait是对象方法,sleep是线程方法
  2. Wait需要和synchronized配合,sleep不需要和synchronized配合
  3. Wait时释放对象锁,sleep不会释放对象锁

park/unpark

unpark既可以在park之前调用,也可以在park之后调用,都可以恢复线程运行

park/unpark与wait/notify区别

  1. Wait,notify/notifyall必须配合object moniter一起使用,而park,unpark不用
  2. Park\unpark 是以线程为单位来阻塞和唤醒线程,而notify只能随机唤醒一个等待线程,notifyAll是唤醒所有等待线程,没有那么精确
  3. Park/unpark可以先unpark,而wair/notify不能先notify
  4. 当前线程调用 Unsafe.park() 方法
  5. 检查 _counter ,本情况为 0,这时,获得 _mutex 互斥锁
  6. 线程进入 _cond 条件变量阻塞
  7. 设置 _counter = 0
  8. 调用 Unsafe.unpark(Thread_0) 方法,设置 _counter 为 1
  9. 唤醒 _cond 条件变量中的 Thread_0
  10. Thread_0 恢复运行
  11. 设置 _counter 为 0
  12. 调用 Unsafe.unpark(Thread_0) 方法,设置 _counter 为 1
  13. 当前线程调用 Unsafe.park() 方法
  14. 检查 _counter ,本情况为 1,这时线程无需阻塞,继续运行
  15. 设置 _counter 为 0

死锁

一个线程需要同时获取多把锁,这时就容易发生死锁
t1 线程获得A对象锁,接下来想获取B对象的锁
t2 线程获得B对象锁,接下来想获取A对象的锁

活锁

活锁出现在两个线程互相改变对方的结束条件,最后谁也无法结束
可增加随机睡眠时间,避免活锁的产生

饥饿

一个线程由于优先级太低,始终得不到 CPU 调度执行,也不能够结束

ReentrantLock

相对于synchronized它具备以下特点

  1. 可中断
  2. 可以设置超时时间
  3. 可以设置为公平锁,默认为不公平(公平锁,按进入阻塞队列的顺序,先进入,先获得锁)
  4. 支持多个条件变量

基本语法
// 获取锁
reentrantLock.lock();
try {
// 临界区
} finally {
// 释放锁
reentrantLock.unlock();
}
可打断
竞争未能获得到锁,进入EntryList阻塞状态可以用interrupt打断,打断后会抛出异常
lock.lockInterruptibly(); //设置可打断

锁超时
lock.trylock //返回值为boolean类型
例:lock.trylock(1,Timeunit.SECONDS)

条件变量
synchronized中也有条件变量,就是waitset,当条件不满足时进入waitset
ReentrantLock支持多个条件变量(Condition),好比synchronized只有一件休息室,而ReentrantLock支持多间休息室,唤醒也是按休息室来唤醒

用法

【JUC】并发编程(二)相关推荐

  1. JUC并发编程二 并发架构--线程运行原理

    sleep与yield的区别 两阶段终止模式

  2. 爬梯:JUC并发编程(二)

    学习资源整理自:B站<狂神说> 书接上回 JUC并发编程 8.线程池(重点) 线程池:三大方法.七大参数.四种拒绝策略 池化技术 程序的执行,本质:占用系统的资源!优化资源的使用==> ...

  3. JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快!

    JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快! 一.ReentrantReadWriteLock(读写锁) 1.读写锁存在 ...

  4. 基于《狂神说Java》JUC并发编程--学习笔记

    前言: 本笔记仅做学习与复习使用,不存在刻意抄袭. -------------------------------------------------------------------------- ...

  5. 多线程进阶=》JUC并发编程

    多线程进阶=>JUC并发编程 1.什么是JUC ​ JUC是java.util.concurrent的简写. ​ 用中文概括一下,JUC的意思就是java并发编程工具包. ​ 并发编程的本质就是 ...

  6. JUC并发编程小总结

    JUC是Java编发编程中使用的工具类,全称为java.util.concurrent.近期在大厂面试中屡屡被问到关于JUC的相关知识点问题,其重要性不言而喻,学好用好JUC可以说是每一个Java程序 ...

  7. 并发编程——JUC并发编程知识脑图

    摘要 并发编程在软件编程中尤为突出和重要,在当今面试或工作中也是不可缺少的.作为一名高级java开发工程师,并发编程的技能已经成为了重要的一项.本博文将详细介绍并发编程中的知识点和知识脑图,帮助大家更 ...

  8. 【尚硅谷】大厂必备技术之JUC并发编程——笔记总结

    [JUC并发编程01]JUC概述 关键字:进程和线程.进程和线程.wait和sleep.并发与并行.管程.用户线程和守护线程 [JUC并发编程02]Lock接口 关键字:synchronized.Lo ...

  9. JUC并发编程中的集合不安全问题源码解析

    JUC并发编程四:集合不安全(Java) 1.List不安全! 代码示例: package unsafe;import java.util.*; import java.util.concurrent ...

  10. ❤️《JUC并发编程从入门到高级》(建议收藏)❤️

    JUC并发编程 1.什么是JUC JUC的意思就是java并发编程工具包,与JUC相关的有三个包:java.util.concurrent.java.util.concurrent.atomic.ja ...

最新文章

  1. 每日一皮:公司来了个程序员鼓励师...
  2. USACO 2.1 健康的好斯坦奶牛 (DFS)
  3. mybatis传递多个参数_Mybatis传递多个参数的4种方式(干货)
  4. 交流电机数字控制系统_敲黑板!新型变频调速控制系统对交流电动机设计的特殊要求...
  5. MySQL找出锁等待
  6. 常见跨域解决方案以及Ocelot 跨域配置
  7. npm 引用子项目模块_Java / Web项目中的NPM模块Browser-Sync
  8. 从《四驱兄弟》到“联想中国”
  9. 创建windows服务,定时监控网站应用程序池
  10. Java校招笔试题-Java基础部分(六)
  11. JAVA设计模式初探之适配器模式(转)
  12. 一文解读聚类中的两种流行算法
  13. 索引超出了数组界限(Microsoft.SqlServer.Smo)
  14. css一些需要注意的东西
  15. 这五款办公神器一个比一个好用
  16. 神经元人体分布大图,人体的神经元图片
  17. 河北省计算机科学专业高校排名,河北省计算机类专业大学排名
  18. 软件构造设计模式III(转载整合)
  19. 全职爸爸,是程序员的加试题
  20. IBM ServerGuide 9.21

热门文章

  1. Unity3D在windows10下小问题解决
  2. 2021年,我推荐你学习的编程语言,各类语言横向对比
  3. datatable分页增加首页和尾页
  4. 98岁国学大师自曝只喜欢18岁的年轻美女
  5. python语言的三种基本结构_Python语言基础分支语句、循环语句.PPT
  6. 装饰工程预结算教程电子书_干货集 | 栏杆百叶工程预结算总结
  7. pyqt5 图片随窗口变化等比例缩放
  8. 山西民生云大同员认证在什么网_山西民生云app下载-山西民生云大同app认证下载手机版 v2.2-91优手机网...
  9. javaWeb的线下服装店管理平台、基于ssm(springboot版本也有)+mysql线下服装销售系统
  10. 我的世界基岩版红石教程(超简单)2