基础篇-多线程Lock<2>

多线程线程安全问题

一、首先分析问题原因

  1. 多线程对同一个数据资源修改,由于拷贝基本数据类型,导致数据资源同时被多线程操作,并且不同步。
  2. 资源的抢占:A线程执行代码块是true,进入执行。这原本应该B线程将其改为false,慢了一拍,A已经进入了代码块。

必须保证多线程并发三特性:可见性 、原子性 、有序性

>>> 可见性
>>> 原子性
>>> 有序性

二、解决多线程问题的方法

  • Synchronized隐式锁
  • Lock显式锁:使用Lock接口的实现类,并使用unlock解锁
  • CAS自旋乐观锁

解决方案

>> Sychronized锁
  • 重量级,悲观锁
  • 用法单一,但保证互斥

大局域(同步方法)小局域(同步代码块)同时使用

[ 类锁 ]:共享静态变量、静态方法、锁class
[ 对象锁 ]:共享成员变量、成员方法、锁this

>> Lock锁
  • 对于构造方法,选择是否公平锁或非公平锁
>>> Lock接口比synchronized块的优势是什么?
Locksynchronized
公平性公平锁/非公平锁非公平锁
释放锁手动自动
互斥性可互斥/非互斥互斥
可见性肉眼可见无法看见
扩展性功能更多,更灵活单一的使用
公平锁与非公平锁
[ 公平锁 ]:多线程先进先出的顺序
[ 非公平锁 ]:多线程抢占机制
Thread的sleep()和Object的wait()
sleep() 不会释放锁,上厕所睡着了
yieId

Running状态进行Ready状态没有退出Runable状态
suspend挂起【不建议使用】
Running状态进行Ready状态没有退出Runable状态

并发工具类
cyclcBarrierconuntdon

newThread(能传runable) 调用start

callable 需要涉及到 FutureTask 可以传递 callable

TimeUnit.SeConDS.sleep 睡5秒

get是阻塞 running
runable没有返回值
callable有阻塞返回值


2.cont++ 不是原子操作

Lock锁 线程安全

死锁:A获取B的锁 B获取A的锁 锁的嵌套

jconsole 检测死锁
Thread



CAS
比较并交换

期望值 == 实际值 再交换

底层采用CAS算法

count++, count–

先加再获取


CAS缺陷 :
循环时间过长,do while
只能保证一个共享原子操作、

ABA问题
原子类可能存在一种现象:
A线程 B线程 C线程
CAS操作成功 需要有预期的值,预期成功会更新值

规避ABA问题,通过版本号
修改的值携带版本号 过程被修改过 和我预期的不同

JDK提供一个原子类


原子类
atomic包 <—原子类集锦

基本类型原子类
引用类型原子类
数组类型原子类
对象属性修改类


互斥锁
只能有一个 执行
阻塞锁
没有获取到锁,线程进入阻塞状态
自旋锁
执行无意义运动,避免阻塞
读写锁
允许多个线程读 一个线程写
公平锁
公平锁 是否排队等待,排队先来先得 Lock 类似队列
非公平锁 释放锁,后面的线程进行抢 synchronized Lock
Lock锁既可以公平也可以非公平


加锁除了Lock 其他会阻塞状态
tryLock 尝试获取锁,如果获取不到值可以有返回值 ,不会阻塞,根据返回值可以判断是否获得锁

公平相当于维护了队列

Lock锁和synchronized 区别

1.synchronized重量级 Lock轻量级
2.synchronized锁自动释放 Lock手动释放
3.synchronized 使用方法固定 ,Lock方法灵活
4.sycnhronized是非公平锁,Lock锁可以设置

Lock 也有等待唤醒机制 condition条件
Lock提供可轮询的锁请求,可以不进入阻塞调用trylock 尝试获取锁 ,
而synchronized 会阻塞


并发工具类

同步屏障(同时执行到i某点)
多线程 跑的快的 中途屏障,用过CyclicVBarrler进入阻塞等待状态 然后await计数,直到await计数为0,再次起跑
特点 : 线程 屏蔽 为0 ,再次i运行 会复位

工具二(执行下一个任务基于上一个任务)
CountDownLatch
常用countDown方法:计数为0 会唤醒一个await阻塞的方法
和工具一是多个互相等待 一起执行

工具二是一个或多个完成之后,才能执行

开始屏障跑 接力需要用方法二 A执行完B才能 跑
5个countDown 只有AB关系 其他列只有起跑有关
竖着 5 横 1

senoahore 信号量
共享锁 多个线程可以执行 ,把线程设置为1 ,类似于synchronized方法 互斥锁
获取许可才可以执行,否则等待
相当于停车车(固定容量) 发许可 还许可

runable callable 区别

守护线程 什么时候结束 ,用户线程结束
比如GC线程

怎么检测死锁 ,出现锁的嵌套 jconslon
线程池 七个参数 执行流程 先判定啥 在判定啥
项目中有没有用过线程池
线程池并发3大特性 可见性 原子性 有序性
内存可见性 ,需要JMM模型

CAS(Compare And Swap)比较交换 ABA问题

锁 lock锁 更加灵活 synchronized 重量级比较死 二lock可以使用rtylock 可 公平可不公平

volatile关键字

	保证主内存数据一致性,禁止指令优化重排序

数据不一致性

线程0x001读取变量int=1存入私有工作内存
主内存变量int=1
线程0x002读取变量int=1存入私有工作内存
	当速度快的线程读取到变量时,而主内存变量需要被修改,未来得及修改已经被速度快的线程读取,导致数据不一致性。
就好比:老师给学生布置了作业任务到黑板(公共区域),学生将作业任务记到本子(学生自己私有的)上就走了,第二天作业没写说没看见。

Volatle数据一致性

	当主内存数据发生变化,需要通知获取过当前数据的元素的线程,需要让线程将新的数据刷新的工作内存中,但是可以多个线程进行修改,不互斥
就好比:老师修改了当日的作业任务到黑板(主内存),学生需要都能看得见新的作业任务到自己的作业本(工作内存),大家必须都可见,而且可以多个老师同时进行修改作业

Sychronized数据一致性

	对主内存加锁进行修改内容前会刷新一次其他线程的内容,互斥其他线程,退出锁时进行一次刷新到其他线程的工作内存
	就好比:布置任务前,需要将内容记录,然后只允许一名老师布置家庭作业,布置完后重写抄一次作业

APi enum
New进入创建状态start()
Runable就绪状态(等待CPU分配)Ready/运行状态Running (或手动yield)
sleep wait join lock 运行状态尝试获取锁,进入Blocked阻塞状态,监测锁,又回到Ruable状态,可能是就绪状态,也可以直接运行,取决于CPU调度器
wait join lock让其他其他线程先获取资源进入Wating状态进行等待状态,一些方法需要唤醒
睡眠进入TimedWaiting延时等待状态
Teminate终止结束

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值