多线程与高并发(三) ,LockSupport AQS VarHandle ThreadLocal

24 篇文章 0 订阅
12 篇文章 0 订阅

目录

day4

一,复习:

1,锁的四种状态及升级过程

2,volatile 可见性和禁止指令重排序怎么实现的

3,synchronized和ReentrantLock有什么不同?

4,各种JUC同步锁

二,TestLockSupport

三,面试题

四,源码阅读技巧

五,阅读原则

day5

一,AQS源码解析

1,画图帮助自己理解记忆

2,AQS核心是

二,VarHandle

1,获取VarHandle

 2,使用VarHandle操作

三,ThreadLocal

1,为什么是线程级的缓存?

2,用途

四,强软弱虚 四种引用       


day4

一,复习:

1,锁的四种状态及升级过程

无锁 -> 偏向锁(只有一个线程) -> 轻量级锁(自旋锁) -> 重量级锁(系统锁)

2,volatile 可见性和禁止指令重排序怎么实现的

可见性:缓存一致新协议

禁止指令重排:JMM 模型里有8个指令完成数据读写,通过其中load和store指令相互组合成4个内存屏障实现禁止指令重排序

3,synchronized和ReentrantLock有什么不同?

synchronizedReentrantLock
加解锁系统自带,系统自动加解锁手动加解锁
等待队列不支持支持
底层实现了四种锁状态的升级CAS+AQS队列来实现

CAS:Compare and Swap,比较并交换。CAS有3个操作数:内存值V、预期值A、要修改的新值B。

AQS使用一个FIFO的队列表示排队等待锁的线程,队列头节点称作“哨兵节点”或者“哑节点”,它不与任何线程关联。

synchronized

AtomicXXX

自旋实现的

4,各种JUC同步锁

LockSupport  灵活的线程工具
ReentrantLock
CountDownLatch倒数的门栓:等待结束
CylicBarrier循环栅栏
Phaser分阶段执行,需要多个参与的。(遗传算法)
ReadWriteLock - StampedLock读 多,写少,保证数据的一致性。读写都需要加锁,避免脏读。
Semaphore限流,同时只允许多少个线程执行。高速口,5个收费窗口
Exchanger 两个线程交换数据使用,阻塞交换。

二,TestLockSupport

支持实现锁

LockSupport.park();//停车

LockSupport.unpark(t);//t线程启动运行

使用wait,notitfy指定线程,比较费劲,LockSupport就想对随意的多。

unpark可以先于park启动,效果是 前者优先于后者。但如果再次调用park 会继续停止

package com.example.demo.thread.t4juc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

public class TestLockSupport {
    public static void main(String[] args){
        Thread t = new Thread(()->{
            for (int i = 0; i < 10; i++) {
                System.out.println(i);
                if (i==5)
                    LockSupport.park();
                if (i==8)
                    LockSupport.park();
                TimeUnitSleep(1);
            }
        });

        t.start();
//        停止后 休眠8秒后重启
//        TimeUnitSleep(8);
//        System.out.println("after 9 SECONDS");
        LockSupport.unpark(t);

    }

    public static void TimeUnitSleep(long timeout){
        try {
            TimeUnit.SECONDS.sleep(timeout);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

三,面试题

实现一个容器,提供两个方法 add size

写2个线程,线程1添加10个元素到容器中,线程2实现监控元素的的个数,个数到5个时,线程2给出提示并结束;

写一个固定容量同步容器,拥有put和get方法吗,以及getCount方法,能够支持两个生产线成以及10个消费线程阻塞调用

四,源码阅读技巧

承认读源码很难

理解别人的思路

要有一定的基础:数据结构的基础  和 设计模式(坦克第一版  23种设计模式)

读思路骨架,不读细节

五,阅读原则

跑不起来不读  :读起来费劲,多态造成找不到具体的子类实现,进行调试debug就会直至子类实现

解决问题就好 - 目的性  : 想象祖传代码

一条线索到底  : 具体实现会有方法套方法,不要整体读,要一条跟进下去,找到具体线索后,在往下读。顺着线读而不是面

无关细节略过 : 边界值 n-1  n+1 之类的 ,只读对当前有用的

一般不读静态

一般动态读法

day5

一,AQS源码解析

1,画图帮助自己理解记忆

(1)方法之间的调用图(每个方法做了什么事情)

(2)类的继承关系图(理清多态关系)

2,AQS核心是

volatile int state值(用来控制首次抢【使用CAS的逾期值确定当前线程是独占】和可重入【如果当前线程是独占,则+1,改变头,表示可重入】)和一个双向链表(存的线程)

CAS(compare and swap的缩写,比较并交换。)的方式入队出队

用CAS代替锁整个链表,从而大大提高了效率

Template Method  模板方法 :父类的方法 由子类实现

Callback Function

父类默认实现

子类具体实现

二,VarHandle

1.9之后出现,指得是指向某个变量的引用,通过这个引用可以找到这个变量,可以做原子性的操作(CAS)。C和C++的实现,使用CPU的元语实现。可以理解为直接操作二进制码。

1.9之前类的成员变量 只能用反射,反射每次操作之前都需要进行检查。

反射的效率低于VarHandle

1,普通属性原子操作

2,比反射快,直接操作二进制码

1,获取VarHandle

 2,使用VarHandle操作

三,ThreadLocal

1,为什么是线程级的缓存?

// -Thread.currenmtThread.map(ThreadLocal,value)

//值设置在当前线程的map中

map是线程的map

2,用途

声明式事务,保证同一个Connection。

线程级的缓存

四,强软弱虚 四种引用       

   java 四种引用 :强软弱虚

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值