![](https://img-blog.csdnimg.cn/20190918135101160.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
多线程
文章平均质量分 80
多线程相关基础,进阶,源码
leo_messi94
这个作者很懒,什么都没留下…
展开
-
多线程(五) -- 并发工具(二) -- J.U.C并发包(二) -- AQS及ReentrantLock原理
开始 Thread-0 持有锁,调用 await,进入 ConditionObject 的 addConditionWaiter 流程 创建新的 Node 状态为 -2(Node.CONDITION),关联 Thread-0,加入等待队列尾部。执行 transferForSignal 流程,将该 Node 加入 AQS 队列尾部,将 Thread-0 的 waitStatus 改为 0,Thread-3 的waitStatus 改为 -1。重入加锁时,让state自增,解锁时,让state自减。原创 2023-02-09 11:52:17 · 338 阅读 · 1 评论 -
多线程(五) -- 并发工具(二) -- J.U.C并发包(六) -- 阻塞队列详解
LinkedBlockingDeque:内部维护的节点对象:public class LinkedBlockingDeque<E> extends AbstractQueue<E> implements BlockingDeque<E>, java.io.Serializable { /** Doubly-linked list node class */ static final class Node<E> {原创 2022-02-27 22:19:49 · 896 阅读 · 0 评论 -
多线程(五) -- 并发工具(二) -- J.U.C并发包(五) -- ConcurrentHashMap详解
1. JDK81.1 重要属性和内部类:// 默认为0// 当初始化时,为-1// 当扩容时,为 -(1 + 扩容线程数)// 当初始化或扩容完成后,为下一次的扩容的阈值大小// 作用在扩容时private transient volatile int sizeCtl;// 整个concurrentHashMap 就是一个Node[]static class Node<K,V> implements Map.Entry<K,V> {}// hash表tran原创 2022-02-24 20:45:23 · 494 阅读 · 0 评论 -
多线程(五) -- 并发工具(二) -- J.U.C并发包(一) -- AQS
大部分JUC包中的工具都是基于AQS的,所以,我们先来学习AQS原理1.AQS原理1.1 概述:全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架1.2 特点:用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁getState - 获取 state 状态setState - 设置 state 状态compareAndSetState - cas 机制设置 state 状态独占原创 2022-02-21 17:10:56 · 107 阅读 · 0 评论 -
多线程(五) -- 并发工具(一) -- 线程池(三) -- Tomcat线程池、Frok/Join线程池
接上篇:ThreadPoolExecutor相关内容7. Tomcat线程池7.1 Tomcat主要分为两个部分:连接器部分:Connnector(NIO EndPoint),负责对外沟通容器部分:Container,负责实现servlet规范,去运行一些servlet组件7.2 Tomcat 在哪里用到了线程池呢:连接器部分中的worker当浏览器向服务器发起一个请求的过程:首先到LimmitLatchLimitLatch 用来限流,可以控制最大连接个数,类似 J.U.C 中的 Se原创 2022-02-21 11:49:47 · 596 阅读 · 0 评论 -
多线程(五) -- 并发工具(一) -- 线程池(二) -- ThreadPoolExecutor相关内容
接上篇线程池概述及自定义线程池3.ThreadPoolExecutor3.1 线程池状态ThreadPoolExecutor 使用 int 的高 3 位来表示线程池状态,低 29 位表示线程数量从数字上比较(第一位是符号位),TERMINATED > TIDYING > STOP > SHUTDOWN > RUNNING这些信息存储在一个原子变量 ctl 中,目的是将线程池状态与线程个数合二为一,这样就可以用一次 cas 原子操作 进行赋值// c 为旧值, ctlO原创 2022-02-21 09:51:16 · 343 阅读 · 0 评论 -
多线程(四) -- 无锁(四) -- UnSafe
待学习原创 2022-02-16 18:42:09 · 176 阅读 · 0 评论 -
多线程(四) -- 无锁(三) -- LongAdder源码
LongAdder的关键域// transient 不会被序列化// 累加单元数组, 懒惰初始化transient volatile Cell[] cells;// 基础值, 如果没有竞争, 则用 cas 累加这个域transient volatile long base;// 在 cells 创建或扩容时, 置为 1, 表示加锁// 加锁是为了保证cells在创建或者扩容时的安全性,使用cas实现的加锁transient volatile int cellsBusy;cellsBusy原创 2022-02-16 17:18:11 · 269 阅读 · 0 评论 -
多线程(四) -- 无锁(二) -- atomic相关原子类
前言java.util.concurrent.atomic并发包提供了一些并发工具类,这里把它分成五类:使用原子的方式更新基本类型AtomicInteger:整型原子类AtomicLong:长整型原子类AtomicBoolean :布尔型原子类原子引用原子数组字段更新器原子累加器1.原子整数以 AtomicInteger 为例讨论它的api接口:通过观察源码可以发现,AtomicInteger 内部都是通过cas的原理来实现的!相关api:public static vo原创 2022-02-16 15:44:53 · 837 阅读 · 0 评论 -
多线程(二) -- 管程(四) -- Park和Unpark
基本使用它们是LockSupport类中的方法// 暂停当前线程LockSupport.park();// 恢复某个线程的运行LockSupport.unpark;情况一:先park再unPark:public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { try { log.debug("====s原创 2022-01-27 11:35:03 · 317 阅读 · 0 评论 -
多线程模式(一)-- 保护性暂停与join源码
定义即Guarded Suspension,用在一个线程等待另一个线程的执行结果要点:有一个结果需要从一个线程传递到另一个线程,让他们关联同一个GuardedObject(作为结果传递的桥梁)如果有结果不断从一个线程到另一个线程那么可以使用消息队列(见生产者/消费者)JDK中,join的实现,Future的实现,采用的就是此模式因为要等待另一方的结果,因此归类到同步模式实现代码示例:public class Test1 { // 线程1 等待线程2的下载结果 publ原创 2022-01-12 18:23:44 · 188 阅读 · 0 评论 -
多线程(二) -- 管程(二) -- Synchronized底层Monitor,轻量级、偏向锁,锁膨胀
Java对象头以 32 位虚拟机为例,普通对象的对象头结构如下,其中的Klass Word为指针,指向对应的Class对象;数组对象:其中 Mark Word 结构为:所以一个对象的结构如下:Monitor(锁)Monitor被翻译为监视器或管程每个java对象都可以关联一个monitor对象,如果使用synchronized给对象上锁(重量级)之后,该对象头的Mark Word中就被设置指向Monitor对象的指针monitor结构如下:刚开始时Monitor中的Owner为原创 2022-01-06 19:24:47 · 1037 阅读 · 0 评论 -
多线程基础(十一)-- 防止CPU占用100%
sleep实现wait实现原创 2022-01-05 10:36:03 · 544 阅读 · 0 评论 -
多线程(二) -- 管程(五) -- 多把锁活跃性及死锁
公平锁和非公平锁:公平锁:非常公平,不能插队,必须先来后到。(ReetrantLock设置带参构造,参数设置为true)非公平锁:竞争上岗,谁抢到资源谁执行。可重入锁:已经拿到了当前锁,在同步块内部,想要再次拿到当前锁,可以自动获得。自旋锁:通过循环进行不断的判断。死锁:线程A持有A锁请求B锁,线程B持有B锁请求A锁。造成死锁。死锁条件:互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。原创 2020-07-20 02:02:34 · 187 阅读 · 0 评论 -
多线程(四) -- 无锁(一) -- CAS无锁并发
前言CAS,Compare And Swap,即比较并交换。Doug lea大神在同步组件中大量使用CAS技术鬼斧神工地实现了Java多线程的并发操作。整个AQS同步组件、Atomic原子类操作等等都是以CAS实现的,甚至ConcurrentHashMap在1.8的版本中也调整为了CAS+Synchronized。可以说CAS是整个JUC的基石。CAS分析比较并交换:比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么就执行,如果不是,就一直循环(自旋锁)。代码示例:在CAS中有三个原创 2020-07-20 01:31:56 · 297 阅读 · 0 评论 -
多线程(十二) -- 内存(一) -- java内存模型JMM
配合volatile一起看,这里先简单记录下,回头再好好理解下。什么是JMMjava内存模型,不存在的东西。是一个概念,一个约定。关于JMM的一些同步的约定线程解锁前,必须把共享变量立刻刷回主存。线程加锁前,必须读取主存中的最新值到工作内存中加锁和解锁是同一把锁主内存和工作内存图解内存间的交互操作:上述图中先store再write。图中三组,再加上lock和unlock。内存交互操作有8种,虚拟机实现必须保证每一个操作都是原子的,不可在分的(对于double和long类型的变量来原创 2020-07-19 22:53:30 · 312 阅读 · 0 评论 -
多线程(五) -- 并发工具(一) -- 线程池(一) -- 自定义线程池
池化技术程序的运行,本质:占用系统的资源。如何优化系统资源的使用:使用池化技术。如线程池、连接池、内存池等等池化技术概述:事先准备好一些资源,有人要用,就来我这里拿,用完之后还给我。如果不适用池化技术,比如线程的创建、销毁都是非常浪费资源的。线程池:好处:降低资源的消耗提高响应的速度方便管理线程复用,可以控制最大并发数、管理线程作用:线程池的作用就2个:减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务可以根据系统的承受能力,调整线程池中工作线程的数原创 2020-07-19 17:31:42 · 431 阅读 · 0 评论 -
多线程进阶(六)-- 阻塞队列BlockingQueue
队列Queue:队列,是一种数据结构。除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的。无论使用哪种排序方式,队列的头都是调用remove()或poll()移除元素的。在FIFO队列中,所有新元素都插入队列的末尾。Queue中的方法:Queue中的方法不难理解,6个,每2对是一个也就是总共3对。看一下JDK API就知道了:注意一点就好,Queue通常不允许插入Null,尽管某些实现(比如LinkedList)是允许的,但是也不建议。阻塞队列Blockin原创 2020-07-19 03:08:49 · 623 阅读 · 0 评论 -
多线程(五) -- 并发工具(二) -- J.U.C并发包(二) -- ReentrantReadWriteLock及StampedLock读写锁
jdk文档:ReentrantReadWriteLock概述大型网站中很重要的一块内容就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务),但是效率非常低。所以在JDK中提供了一种读写锁ReentrantReadWriteLock,使用它可以加快运行效率。读写锁表示两个锁,一个是读操作相关的锁,称为共享锁;另一个是写操作相关的锁,称为排他锁。我把这两个操作理解为三句话:读和读之间不互斥,因为读操作不会有线程安全问题写和写之间互原创 2020-07-19 01:29:18 · 173 阅读 · 0 评论 -
多线程进阶(五)-- Callable,Future,FutureTask
Callable:Callable和Runnable差不多,两者都是为那些其实例可能被另一个线程执行的类而设计的,最主要的差别在于Runnable不会返回线程运算结果,Callable可以(假如线程需要返回运行结果)与Runnable的区别:可以有返回值可以抛出异常方法不同,run/callFutureFuture是一个接口表示异步计算的结果,它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。Future提供了get()、cancel()、isCancel()、isDon原创 2020-07-18 00:35:58 · 179 阅读 · 0 评论 -
多线程(五) -- 并发工具(二) -- J.U.C并发包(七) -- CopyOnWriteArrayList()解析及为什么要复制
常用集合在多线程下的问题:代码:public class TestCopyOnWriteArrayList { public static void main(String[] args) { List list = new ArrayList(); for (int i = 0; i < 100; i++) { new Thread(() -> { list.add(UUID.randomUU原创 2020-07-17 19:54:50 · 1322 阅读 · 5 评论 -
多线程(二) -- 管程(七) -- 生产者消费者模型、虚假唤醒、Condition实现精准通知
什么是生产者/消费者模型一种重要的模型,基于等待/通知机制。生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点:生产者生产的时候消费者不能消费消费者消费的时候生产者不能生产缓冲区空时消费者不能消费缓冲区满时生产者不能生产生产者消费者模型的优点:解耦。因为多了一个缓冲区,所以生产者和消费者并不直接相互调用,这一点很容易想到,这样生产者和消费者的代码发生变化,都不会对对方产生影响,这样其实就把生产者和消费原创 2020-07-17 16:45:05 · 304 阅读 · 0 评论 -
多线程(五) -- 并发工具(二) -- J.U.C并发包(三) -- Semaphore使用
概述:Semaphore是非常有用的一个组件,它相当于是一个并发控制器(限制并发数),是用于管理信号量的。构造的时候传入可供管理的信号量的数值,这个数值就是控制并发数量的,我们需要控制并发的代码,执行前先通过acquire方法获取信号,执行后通过release归还信号 。每次acquire返回成功后,Semaphore可用的信号量就会减少一个,如果没有可用的信号,acquire调用就会阻塞,等待有release调用释放信号后,acquire才会得到信号并返回。Semaphore分为单值和多值两种:原创 2020-07-17 02:28:04 · 207 阅读 · 0 评论 -
多线程(五) -- 并发工具(二) -- J.U.C并发包(四) -- CountDownLatch与CyclicBarrier的使用
CountDownLatchCountDownLatch主要提供的机制是当多个(具体数量等于初始化CountDownLatch时count参数的值)线程都达到了预期状态或完成预期工作时触发事件,其他线程可以等待这个事件来触发自己的后续工作。值得注意的是,CountDownLatch是可以唤醒多个等待的线程的。到达自己预期状态的线程会调用CountDownLatch的countDown方法,等待的线程会调用CountDownLatch的await方法。如果CountDownLatch初始化的count值为原创 2020-07-17 01:46:27 · 158 阅读 · 1 评论 -
多线程(一) -- java线程(四) -- interrupt方法详解
https://www.jianshu.com/p/ccb493a2df21https://www.cnblogs.com/greta/p/5624839.htmlhttps://www.cnblogs.com/xrq730/p/4856361.html原创 2020-07-16 23:27:50 · 412 阅读 · 0 评论 -
多线程(二) -- 管程(六) -- ReentrantLock详解
概述:ReentrantLock,一个可重入的互斥锁,它具有与使用synchronized方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。基本使用:public class ReentrantLockTest1 { private Lock lock = new ReentrantLock(); public void test() { try { lock.lock(); for (int i =原创 2020-07-16 23:26:19 · 763 阅读 · 0 评论 -
多线程(二) -- 管程(三) -- 线程通信wait(),notify(),notifyAll()
结论:wait()方法可以使调用该线程的方法释放共享资源的锁,然后从运行状态退出,进入等待队列,直到再次被唤醒。释放锁notify()方法可以随机唤醒等待队列中等待同一共享资源的一个线程,并使得该线程退出等待状态,进入可运行状态。不释放锁notifyAll()方法可以==使所有正在等待队列中等待同一共享资源的全部线程从等待状态退出,进入可运行状态 ==最后,如果wait()方法和notify()/notifyAll()方法不在同步方法/同步代码块中被调用,那么虚拟机会抛出java.lang.Il原创 2020-07-16 18:50:12 · 254 阅读 · 0 评论 -
多线程(三) -- 内存(二) -- Volatile详解
Volatile的作用:先说结论:保证变量对所有线程的可见性,但不能保证原子性。禁止指令重排序优化。volatile不会导致阻塞内存与缓存与并发:要了解volatile,就要先对CPU,CPU cache和主存有所有了解。主存就是我们平时说的内存,它的读写速度很慢,而CPU运算速度很快,为了弥补二者的差异,在CPU和主存之间引入了CPU Cache,现在很多CPU都会有三层Cache,分别称为L1,L2和L3,其中L1最靠近CPU,缓存速度也最快,L1这块缓存被分为了两个部分,一部分是指原创 2020-07-16 18:10:42 · 1407 阅读 · 0 评论 -
多线程(二) -- 管程(一) -- Synchronized详解
多线程引发的问题:脏读:一个常见的概念。在多线程中,难免会出现在多个线程中对同一个对象的实例变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是"脏读",也就是取到的数据其实是被更改过的。代码示例:public class ThreadDomain13 { private int num = 0; public void addNum(String userName) { try { if ("a".equals(userName)原创 2020-07-16 01:12:59 · 320 阅读 · 0 评论 -
多线程(一) -- Java线程(三) -- join方法详解,join阻塞的到底是什么线程
理解join()方法之前请确保对wait()/notify()/notifyAll()机制已熟练掌握。join()方法的作用是等待线程销毁。join()方法反应的是一个很现实的问题,比如main线程的执行时间是1s,子线程的执行时间是10s,但是主线程依赖子线程执行完的结果,这时怎么办?可以像生产者/消费者模型一样,搞一个缓冲区,子线程执行完把数据放在缓冲区中,通知main线程,main线程去拿,这样就不会浪费main线程的时间了。另外一种方法,就是join()了。例一:阻塞mian线程public原创 2020-07-15 16:11:02 · 3032 阅读 · 2 评论 -
多线程(一) -- Java线程(二) -- Thread类方法详解:sleep、yield、优先级等
Thread类中的方法调用方式:学习Thread类中的方法是学习多线程的第一步。在学习多线程之前特别提出一点,调用Thread中的方法的时候,在线程类中,有两种方式,一定要理解这两种方式的区别:1.this.XXX()这种调用方式表示的线程是线程实例本身2.Thread.currentThread.XXX()或Thread.XXX()上面两种写法是一样的意思。这种调用方式表示的线程是正在执行Thread.currentThread.XXX()所在代码块的线程当然,这么说,肯定有人不理解两者之间的原创 2020-07-15 15:02:42 · 346 阅读 · 0 评论 -
多线程(一) -- Java线程(一) -- 创建线程及线程状态
进程和线程和协程进程:进程,直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,上级挂靠单位是操作系统。操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源),进程是资源分配的最小单位。可以理解成windows中运行的一个个的程序,一个程序就是一个进程。线程:进程中独立运行的子任务。比如QQ.exe运行时就有很多子任务在同时运行,比如聊天子任务,下载文件子任务。。。这些子任务就可以理解成一个个的线程。线程是操作系统调度原创 2020-07-15 00:42:55 · 326 阅读 · 0 评论