并发编程知识点整理

    技术2022-07-11  136

    一.进程,线程,协程

    进程是操作系统分配资源的最小单位;

    线程是程序执行得最小单位;

    协程是更轻量级,资源占用更小的线程;比方说100万个线程占大概1T,100万个协程占1G。

    线程该如何创建呢

    new Thread(()->{});   thread.start()实现 Runnable;实现Callable,带有返回值,使用的时候submit;线程池。

    thread.start的运行过程是这样的

    线程的状态如图

    那么既然是多线程,就会存在安全问题,那么该如何保证线程的安全性呢

    二. 锁

    1.CAS

    CPU速度是远远大于硬盘的速度,大概100万倍,所以其中就得加缓存来缓解这种尴尬

    java内存模型

    如图所示,可以看的出来,当多个线程操作一个数据时,是把数据读到自己的内存中进行操作的,那么这种闭门造车的方式来操作数据是肯定会有数据安全的问题的,如何解决这种问题呢?第一种就是锁先看一下CAS

    cas顾名思义,compare and swap,比较并替换。但是这样会产生ABA的问题,意思就是你女朋友跟你分了又复合了,但是期间又谈了几个男朋友,但是你不知道。如何解决呢,记录一下,多谈了一个就加一。cas的就整个乐观锁,版本号加一的那种。自己跟自己玩,是一种轻量级锁。

     

    2.Synchronize

    跟上边的锁不一样,这个锁是一种要麻烦操作系统老大哥的操作,等老大哥闲下来了,会给他一把锁,所以,对比于上边性能低,是一把重量级锁。

    synchronize1.6之后呢,做了一个优化,是存在一个锁升级的过程的即 无锁->偏向锁->轻量级锁->重量级锁,如图

    介绍几个概念

    适应性自旋锁:获取成功的下次自旋时间就长一点,没获取到的下次就短一点

    锁消除:          如果不存在多线程竞争情况下的加锁,将会消除锁,判断依据是变量逃逸

    锁粗化:          例如循环加锁,会将锁从循环里拿出来放在外边

    再来说一下原理吧

    1. 代码层面,Synchronize

    2. 优化层面,锁升级   无锁->偏向锁->轻量级锁->重量级锁

    3. 字节码层面,monitorenter,monitorexit

    4. native层面,lock cmpex

    5. 硬件层面,锁住了北桥信号

    3.基于AQS实现的锁

    ReentrantLock,ReentrantReadWriteLock,Condition

    AQS底层其实就是一个双向链表,根据status的值来判断是否当前代码被加锁,如果等于0,就获得锁,大于0, 是重入锁;

    如果是公平锁,就放入队列中,如果是非公平锁就tryLock一下,如果失败了再放入队列,其实就是一个插队的区别。

    属于一种轻量级锁。锁粒度更小。

    CyclicBarrier和CountDownLatch的区别是,CountDownLatch是1个或者多个线程等其他的线程完成;CyclicBarrier是N个线程互相等待,CountDownLatch计数器不能重置,CyclicBarrier计数器可以重置。

    接下来介绍另一种解决数据可见性的方案

    三 volatile

    volatile就是让自己内存中指定的数据失效,不得不从主存中拿数据,这样就可以了,但是缺点也很显然,一个是性能低,一个是多线程下无法保证数据安全。

    操作系统层面来说原理的话,由于cpu,内存,硬盘速度差别特大,数据不一致,所以采用的协议是MESI缓存一致性协议。

    除了保证数据可见性,还能防止重排序。重排序会导致什么问题呢,咱们比方说

    防止重排序呢实现原理就是加了一个内存屏障,类似的还有

    比如happen-before原则如下

    依赖情况下,顺序执行传递性原则Thread.startThread.joininterruptsynchronizedvolatilefinanzied

    as-if-serial的意思是不管咋重排序都不能对结果产生影响。

    四 ThreadLocal原理

    ThreadLocal是一个线程传值的工具。

    说一下java 的四种引用

    1.强引用  : ThreadLocal t = new ThreadLocal();宁愿抛出OOM也不回收这个对象

    2.软引用  :    内存不够了就会回收这个对象

    3.弱引用 :  垃圾回收器一看到它就会回收

    4.虚引用 :  比弱引用更弱,幽灵引用,一般被用来管理堆外内存

    如图,threadlocal对象有两个引用,一个是new的强引用,一个是entry的弱引用,当强引用不存在时,GC看到弱引用会干掉他,导致key为null;而map的生命周期跟thread是一样的,所以无法回收data导致内存泄漏,一般不用的时候在调用一下remove方法

    Processed: 0.012, SQL: 9