并发
2021-05-28 17:49:10 2 举报
AI智能生成
CAS、AQS
作者其他创作
大纲/内容
Synchronized
javap --> 反编译代码:有<font color="#c41230"><b>一个monitor enter</b></font>指令,<b><font color="#c41230">多个monitor exit</font></b>指令(<font color="#f15a23">避免发生异常导致不能monitor exit</font>)
AQS
<ul><li><font color="#c41230"><b>原理</b></font></li></ul>
1、State(<font color="#c41230"><b>volatile</b></font>)<font color="#f15a23"></font><br>
<ul><li><font color="#f15a23">模板模式</font>:根据自己同步器需要满足的性质实现线程获取和释放资源的方式(修改同步状态变量State的方式)</li></ul>
<ul><li>三种访问方式</li></ul>
1、getState()
2、setState()
3、compareAndSetState():<font color="#c41230"><b>CAS保证了节点的原子性</b></font><br>
<ul><li>使用volatile保证了<font color="#c41230"><b>head、tail节点</b></font>操作中的<font color="#c41230"><b>有序性和可见性</b></font></li></ul>
2、<font color="#c41230">CLH 内部队列</font>
<ul><li><font color="#f15a23">Node节点</font></li></ul>
1、wateStatus<br>
<ul><li>CANCELLED:1 说明该线程中断或者等待超时,需要<font color="#c41230">移除该线程</font></li></ul>
<ul><li>SIGNAL: -1 处于唤醒状态,只要<font color="#c41230">前继结点释放锁,就可执行该线程</font></li></ul>
<ul><li>CONDITION: -2 与<font color="#c41230">Condition(条件队列)</font>相关,该标识的结点处于等待队列中;当其他线程调用了<font color="#c41230">Condition的signal()方法</font>后,CONDITION状态的结点将<font color="#f15a23">从等待队列转移到同步队列中</font>,<font color="#f15a23">等待获取同步锁</font>。</li></ul>
<ul><li>PROPAGATE: -3 在<font color="#c41230">共享模式</font>中,该状态标识结点的线程处于<font color="#c41230">可运行状态</font>。</li></ul>
2、prev(<font color="#f15a23">阻塞队列</font>):是同步线程队列中保存的<font color="#c41230"><b>前置节点</b></font>的地址。
3、next(<font color="#f15a23">阻塞队列</font>):是同步线程队列中保存的<b><font color="#c41230">后续节点</font></b>的地址。
4、thread:<font color="#c41230">同步线程队列</font>主要存储的<font color="#c41230">线程信息</font>。
5、nextWaiter(<font color="#f15a23">条件队列</font>):条件队列是使用单向列表保存的,用<br>nextWaiter来连接。
子主题<br>
<ul><li><font color="#f15a23">2种队列</font></li></ul>
1、<font color="#c41230">同步队列</font>
原理:当线程获取资源失败后,就进入同步队列的<font color="#c41230"><b>尾部保持自旋等待;</b></font>不断判断自己<font color="#c41230">是否是链表的头节点;</font>如果是<font color="#f15a23">头节点,就不断参试获取资源</font>,获取<font color="#c41230">成功后则退出同步队列</font>。
2、<font color="#c41230">条件队列</font>
原理:是为Lock实现的一个基础同步器,并且一个线程<font color="#c41230">可能会有多个条件队列</font>,只有在使用了<font color="#c41230">Condition才会存在条件队列</font>。
3、两种资源共享的方式
<font color="#f15a23">1、独占锁</font>
概念:同一时刻<font color="#c41230"><b>只允许一个线程</b></font>访问共享资源
类
<ul><li>ReentrantLock</li></ul>
<font color="#f15a23">2、共享锁</font>
概念:同一时刻<font color="#c41230"><b>允多个线程</b></font>访问共享资源<br>
类
<ul><li>Semaphore</li></ul>
核心思想(<font color="#c41230">可用于限流方案</font>):可以认为Synchronized代表的是一把锁,那么<font color="#c41230"><b>Semaphore就是多把锁</b></font>。
核心方法
1、Semaphore(int permits):构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。
2、Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量。
3、void acquire():从此信号量获取一个许可前线程将一直阻塞。相当于一辆车占了一个车位。
4、void acquire(int n):从此信号量获取给定数目许可,在提供这些许可前一直将线程阻塞。比如n=2,就相当于一辆车占了两个车位。
5、void release():释放一个许可,将其返回给信号量。就如同车开走返回一个车位。
6、void release(int n):释放n个许可。
7、int availablePermits():当前可用的许可数。
<ul><li>CountDownLatch</li></ul>
1、new CountDownLatch(4):此时会创建一个<font color="#f15a23">AQS的同步队列</font>,并把创建CountDownLatch 传进来的计数器赋值给AQS队列的<b> <font color="#c41230">state(4).</font></b>
2、countDownLatch.wait():会创建一个节点,加入到AQS阻塞队列,并同时把当前线程挂起。
3、countDownLatch.down():AQS内部是通过<font color="#f15a23">释放锁的方式,对state进行减1操作</font>,当state=0的时候,将AQS阻塞队列里的节点线程全部唤醒。
4
LockSupport.park():作用是<font color="#f15a23">阻塞当前线程</font>
LockSupport.unpark(Thread):停止<font color="#f15a23">阻塞某线程</font><br>
实质:实质都是通过UnSafe类使用了CPU的原语
作用:让<font color="#c41230">排队的线程</font>阻塞掉(<font color="#c41230">停止其自旋,自旋会消耗CPU资源</font>),并在需要的时候,可以方便的<font color="#c41230">唤醒阻塞掉的线程</font>。
CAS
<ul><li><font color="#c41230"><b>原理</b></font></li></ul>
1、依赖Unsafe类中的<font color="#c41230">compareAndSwapInt</font>,借助<font color="#f15a23">C来调用CPU底层</font>指令实现的。<br>
2、CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当<font color="#c41230">预期值A和内存值V相同</font>时,将内存值V修改为B,否则什么都不做(然后自旋)。
<ul><li><font color="#c41230">实现类</font></li></ul>
AtomicInterger(<font color="#c41230">限流</font>)
<ul><li><font color="#c41230">缺点</font></li></ul>
1、ABA问题。
<ul><li><font color="#f15a23">AtomicStampedReference/AtomicMarkableReference</font>来处理会发生ABA问题的场景,主要是在对象中额外再<font color="#c41230">增加一个标记</font>来标识对象是否有过变更。</li></ul>
2、循环时间长开销大。<font color="#c41230">自旋CAS</font>如果长时间不成功,会给CPU带来非常大的执行开销。
线程
线程池
<font color="#c41230">四种线程池</font>
1、SingleThreadExecutor<br>
<font color="#c41230"><b>单例线程池:</b></font>循环使用,只会有一个线程。
2、CachedThreadPool
<font color="#c41230"><b>缓存线程池</b></font>:可<font color="#f15a23">重用线程</font>,如果没有可用的线程,既新增;移除那些<font color="#f15a23">已有 60 秒钟未被使用的线程</font>。因此,长时间空闲的线程池不会占用任何资源。
3、FixedThreadPool
<font color="#c41230"><b>定长线程池</b></font>:指定工作线程<font color="#f15a23">数量的线程池</font>,提交一个任务新建一个线程,直到饱和;如何工<font color="#f15a23">作任务达到线程的最大数,既存入池队列中</font>。
4、ScheduledThreadPool
<font color="#c41230"><b>周期线程池</b></font>:创建一个线程池,它可安排在给定延迟后运行<font color="#f15a23">命令或者定期</font>地执行。(<font color="#c41230">延时</font>)
<font color="#c41230">核心参数</font>
1、<font color="#f15a23">corePoolSize</font>:核心线程数
<ul><li>核心线程会<font color="#c41230">一直存活</font>,及时没有任务需要执行</li></ul>
<ul><li>当线程数小于核心线程数时,即使有线程空闲,线程池也会<font color="#c41230">优先创建新线程处理</font></li></ul>
<ul><li>设置allowCoreThreadTimeout=true(默认false)时,<font color="#c41230"><b>核心线程会超时关闭</b></font></li></ul>
2、<font color="#f15a23">queueCapacity</font>:任务队列容量(阻塞队列)
<ul><li>当核心线程数达到最大时,新任务会放在队列中排队<font color="#c41230">等待执行</font></li></ul>
3、<font color="#f15a23">maxPoolSize</font>:最大线程数
<ul><li>当线程数<b><font color="#f15a23">>=corePoolSize</font></b>,且任务队列已满时。线程池会<font color="#f15a23">创建新线程来处理任务</font></li></ul>
<ul><li>当线程数<font color="#f15a23"><b>=maxPoolSize</b></font>,且任务队列已满时,线程池会<font color="#c41230"><b>拒绝处理任务而抛出异常</b></font></li></ul>
4、<font color="#f15a23">keepAliveTime</font>:线程空闲时间
<ul><li>当线程空闲时间达到keepAliveTime时,线程会退出,直到<font color="#c41230"><b>线程数量=corePoolSize</b></font></li></ul>
<ul><li>如果<font color="#f15a23">allowCoreThreadTimeout=true</font>,则会直到线程数量=0</li></ul>
0 条评论
下一页