锁的使用(零碎笔记)

启动线程的三种方式

线程就是一个程序里不同的执行路径

  1. 通过继承Thread
  2. 通过实现Runnable接口
  3. Executors.newCachedThrad(线程池启动,他里面启动线程的方式是依赖前面两种的)

在这里插入图片描述

关于线程的方法

sleep:表示调用这个方法的线程休眠一段时间,这段时间里,该线程不会被cpu调度
yield:表示该线程离开一会,在cpu中他会进入一个等待队列,但是他下一次还是可能被cpu调度,只是可能性比较小
join:在自己的线程里调用该方法是没有意义的,他应该在自己的线程里调用别的线程的方法,然后该线程会跑到别的线程那里执行,当这个线程执行完之后才会回到本线程,它用于等待一个线程的结束
interupt:会抛出一个异常,在catch块里面做出反应
在这里插入图片描述

线程状态的迁移图

在这里插入图片描述

synchronized不能锁String常量Integer,LONG ,不要用这种基础的数据类型
synchronized(悲观锁,系统自动解锁):
下面两种都是锁的当前实例this对象
在这里插入图片描述
在这里插入图片描述
下面这两种锁的是当前.class文件的Class对象
在这里插入图片描述
synchronized是可重入锁:一个同步方法可以调用另一个同步方法,一个线程已经拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁,也就是说synchronized获得的锁是可重入的,他必须是重入锁:
在这里插入图片描述
程序在执行过程中,如果出现异常,默认情况锁会释放,如果不想释放锁就catch住异常。
在这里插入图片描述
锁定方法 非锁定方法 同时执行
synchronized底层实现(保证原子性,hotspot的实现)
他会在对象的头部的某两个字节指定是什么锁,和在头上指定是哪个线程的锁

JDK早期的 他的实现是重量级的 ->OS
后来的改进
锁升级的概念 (看我就是厕所所长)

sync(Object) :
当第一个线程进来的时候,先在这个object的头上
markword 记录这个线程ID(偏向锁)
如果有线程争用:升级为 自旋锁(在用户态不经过内核,占cpu),旋了十次之后
升级为重量级锁 -> OS(不占用CPU资源)
执行的时间短(加锁代码),线程数少适合用自旋锁
执行的时间长,线程数多适合用系统锁
Lock:很多都是自旋锁(CAS)

volatile:尽量不要修饰引用,引用里面的值改变了他是观察不到的
作用:每次写都会被线程读到
在这里插入图片描述
线程的可见性
在这里插入图片描述
关于volatile在单例模式中的应用
饿汗式:
在这里插入图片描述
懒汉式(线程不安全)
在这里插入图片描述
解决线程不安全问题:
下面线程安全但是效率低
在这里插入图片描述
锁优化的过程
在这里插入图片描述
双重检查
在这里插入图片描述
这个单例要加上volatile
在这里插入图片描述
不加volatile,某个线程可能拿到半初始化的对象
在这里插入图片描述
存储过程写在数据库里

volatile并不能保证多个线程共同修改running变量时所带来的不一致问题,也就是说volatile并不能替代synchronized运行下面的程序

在这里插入图片描述
锁优化:同步代码块中的语句越少越好
锁细化
在这里插入图片描述

注意:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
CAS(无锁优化 自旋 乐观锁)compareAndSwap(jdk11)compareAndSwap(jdk8) 效率高
先get想要的值作为期望值,防止后续进行cas操作的时候改变了
在这里插入图片描述
在这里插入图片描述
Atomicxxx的类实现了cas操作
在这里插入图片描述
LongAddr(分段锁)也是(他在线程数非常高的情况下有优势)
在这里插入图片描述
他内部用了分段锁
在这里插入图片描述
在这里插入图片描述

ABA问题:
这个问题就是说我们想要对一个值进行cas操作,但是另外一个线程把这个值A修改为B,然后又修改为A,这种情况我们基本数据类型的话是可以不解决的,如果是一个对象(举例:如果你和你的对象复合后,他可能经过了n多个男人),就可能有问题,想要解决我们就用如下方法:
在这里插入图片描述

加版本号解决
A 1.0
B 2.0
A 3.0
cas(version)
compareAndSwap的都是在下面这个unsafe类实现的
在这里插入图片描述
reentrantlock(他也是可重入的,需要手动解锁)用于替代synchronized
使用:
在这里插入图片描述
使用2
在这里插入图片描述
在这里插入图片描述
使用2
在这里插入图片描述
在这里插入图片描述
它可以传一个参数进去就变成了公平锁(当一个线程进来了,他会先看看队列里面有没有线程,有线程就进队列,可以保证到来的线程排队执行)
在这里插入图片描述
ReentranLock和sycr的区别
在这里插入图片描述
CountDownLatch:相当于一个门栓,当latch减去为0的时候才会继续执行后续的代码
countDown(内部CAS操作):他是可以同一个线程一直countDown的
在这里插入图片描述
下面用join也可以实现同样的功能:
在这里插入图片描述
CyclicBarrier:
使用:只有到了一定数量的线程的时候才发车
在这里插入图片描述
在这里插入图片描述

Phaser(面试问的少)
arriveAndAwaitAdvance:等待进入下一个阶段
arriveAndDeregister:不进入下一个阶段了
在这里插入图片描述
下面是加一个
在这里插入图片描述

阶段自己定义:
定义多少个线程到达才能进入下一阶段
在这里插入图片描述

onAdvance是在栅栏被推到后自动调用
在这里插入图片描述
ReadWriteLock(read共享锁,write排他锁) ->StampedLock
使用:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
写操作加写锁(这个是排他锁),读加读锁(可以多个线程一起读,但是不会读到写了一半的数据)。

Semaphore(信号量):常用于限流场景
使用:
acquire():获得取得锁(取得了才能往下执行)
release():释放信号量
在这里插入图片描述
构造器参数表示有几个线程可以同时运行
在这里插入图片描述
参数2:true表示是公平的锁
在这里插入图片描述

Exchanger(交换器,只能两个线程之间):
用于线程之间交换数据
在这里插入图片描述
在这里插入图片描述
没交换数据之前会阻塞
在这里插入图片描述
LockSupport
park:让当前线程阻塞
在这里插入图片描述
unpark:线程不阻塞(可以在park之前调用)
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值