多线程基础
第一章 多线程
进程:一个独立的应用程序
线程:一条执行路径
1.1 线程安全
发生前提:
1 必须要有俩个以上的线程,需要发生同步
2 多个线程想同步,必须要用到一把锁
3 保证只有一个线程在运行
原理:
1 有一个线程已经拿到了锁,其他的线程已经获得了CPU的执行权,一直在排队,等待其他线程释放锁。
2 锁是什么时候释放? 在代码块执行完毕或者抛出异常都会被释放掉
3 锁已经被释放掉,其他线程开始获取锁进去同步中区
4 锁的资源竞争,多个
5 死锁的问题
缺点:效率非常低
同步函数(函数用synchronized修饰)和同步代码块(this)可以保持同步
静态同步函数不使用this锁,当一个方法被static修饰,存放在永久区,当class文件被加载的时候被初始化,使用当前字节码文件
1.2 死锁(多线程)
发生场景:同步中嵌套同步,无法释放,一直处于等待状态,变为死锁
1.3 多线程3大特性
a原子性:线程唯一,保证线程安全问题
b可见性:java内存模型
c有序性:join、wait、notify(多线程之间的通讯)
1.4 java内存模型(多线程的可见性 JVM)
【 java内存结构(JVM的内存分配)】
决定了线程与另一个线程是否可见
1.主内存 :存放共享的全局变量
2.私有本地内存 :本地线程的私有变量 ,以及主内存中的共享数据副本,最终会更新主内存的数据
1.5 重排序
cpu会对代码执行实现优化,不会对有依赖关系的进行重排序,代码的执行顺序可能会发现变化,但是执行结果不会发生变化。
多线程可能会发现影响。
1.6 Volatile
作用:
1.保证线程之间可见,但是不保证原子性;
2.被volatile修饰的变量,主内存被修改之后可以立即通知其他私有本地内存。保证线程之间数据的可见性
3.可使用atomicinteger的原子类保证线程的安全
4.禁止重排序
1.7 AtomicInteger
jdk1.5引入的原子类,解决线程的安全问题
第2章 多线程之间的通讯
2.1
wait() notify()、notifyAll()3个方法都是定义在object方法中,都可用来控制线程的状态,最终调用了jvm的native方法,随着jvm运行平台的不同可能有些许的差异
1. wait 方法:交出该对象的使用权,当前线程处于等待状态
2. notify() :通知某个等待该对象控制权的线程可以运行了
3. notifyAll(); 通知所有等待该对象的控制权的线程可以运行了
注:一定要在线程同步中使用,并且是一个锁的资源
2.2 wait() 和sleep()区别
1.sleep() 是属于Thread类中的,规定了线程的暂停时间,此时间内不参与CPU的争抢,但是它的监控状态一直保持着,当指定的时间到了又会自动恢复到运行状态,此过程中不会释放对象锁。
2.wait() 是属于object类中的方法,当对象调用此方法时,线程会释放此对象锁,进入等待此对象的等待锁定池,而只有针对此对象的notify()方法时,本线程才会进入对象等待锁定池准备
2.3 Join
让出当前线程的执行权,让别的线程执行完毕,
2.4 ThreadLocal
为本地线程提供一个局部变量,不共享,Map
第3章 java并发包并发队列
3.1 Vector和ArrayList区别
实现原理都是通过数组,,查询速度快,其慢
Vector 线程安全,效率不高 添加方法被synchronized
ArrayList 效率高
3.2 HashTable 和HashMap 的区别
HashTable 线程安全 添加方法被synchronized
HashMap线程不安全
3.3 Collections.synchronized*(m)
将不安全的集合转换为安全的集合,上锁
3.4 jdk1.5的并发包
1.ConcurrentHashMap 线程安全,采用分段锁机制,效率高
2.CountDownLatch(jdk1.5的并发包) 计数器,调用countDown方法减一,当计数器为0时,wait() 方法之后的代码才会执行。
3.CyclicBarrier 计数器,初始化规定了一个数目,然后计算调用了CyclicBarrier.await()进入等待的线程数,当线程达到了这个数目时,所有进入等待的的线程都会被唤醒并继续执行。
4.Semaphore 一种基于计数器的信号量,设定一个阈值,多个线程竞争获取许可信号,线程结束后释放,超过阈值后,线程申请许可信号将会被阻塞。Semaphore可以用来构建一些对象池,资源池之类的,比如数据库连接池,我们也可以创建计数为1的Semaphore,将其作为一种类似互斥锁的机制,这也叫2元信号量,表示两种互斥状态。它的用法如下:
availablePermits 函数用来获取当前可用的资源数量
wc.acquire(); //申请资源
wc.release(); //释放资源
3.5 并发队列
1. ConcurrentLinkedQueue 无界高性能队列
2. BlockingQueue 有界阻塞队列 (生产者和消费者)
阻塞与非阻塞区别
有等待时间
第4章 线程池
【合理配置:CPU密集、IO密集】
4.1 作用
1.降低资源消耗 (重复利用线程,减少等待cpu调度时间)
2.提高响应速度 (当任务到达时,任务可以不需要等到线程创建就能立即执行)
3.管理线程 (线程的创建和分配)
4.2 实现原理
使用阻塞队列
4.3 java 管理线程的核心-----ThreadPoolExecutor
参数:
核心池大小(codePoolSize)
最大线程池大小(maximumPoolSize)
终止时间(keepAliveTime)
超时秒数(unit)
4.4 Executor封装好了4种线程池
newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。核心线程池为0
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。核心线程池为1
4.5 Future模式
使用callback 执行线程,获取线程执行结果,
4.6 线程池配置多少合适? CPU密集、IO密集
CPU密集【进程花费了绝大多数时间在计算上】 :线程数和CPU数相同
IO密集【等待I/O上花费了大多是时间】 :(操作数据库、IO等待、阻塞、休眠) 配置为 2*CPU数
4.7 java的锁机制
1.悲观锁,使用场景,查询量小,
每次取数据的时候上锁
Select * from date where id=1 for update【排他锁】
缺点:执行效率低
- 乐观锁
就是每次去拿数据的时候认为别人不会去修改,所以不会上锁,加版本控制,
Update date set status=1,version= version +1 where version =1
- 分段锁
ConcurrentHashMap 采用分段锁机制,16个锁的数组,提高请求效率
- 重入锁
锁传递给下一个方法,重复使用
非重入锁(死锁)
- 读写锁 【ReentrantReadWriteLock】
Java 读写锁的机制:读-读能共存,读-写不能共存,写-写不能共存
- CAS无锁【AtomicInteger】
原子类底层实现线程安全 :通过CAS无锁机制
CAS的3个参数:V表示要更新的变量,E表示预期值,N表示新值。
仅当V值等于E值时,才会将 V的值设为N,如果V值和E值不同,则说明已经有其他线程做了更新,则当前线 程什么都不做。最后,CAS返回当前V的真实值
- 自旋锁
是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成busy-waiting
8.排它锁
9.分布式锁
第5章 Disruptor框架
注:第3方的多线程框架
5.1 Disruptor设计来解决队列速度慢的问题:
- 底层采用CAS无锁机制,不需要频繁的上下文切换,调用时不需要在用户态与内核态之间切换。
- 用 环形数组结构ringbuffer 来取代队列容器
- Ringbuffer 主动推送信息到消费者----------观察者模式
怎么知道推给那个消费者?
Disruptor.headleEventWith(new LongHeadler()); 注册消费者
- 为了避免垃圾回收,采用数组而非链表。同时,数组对处理器的缓存机制更加友好。
- 元素位置定位
- 数组长度2^n,通过位运算,加快定位的速度。下标采取递增的形式。不用担心index溢出的问题。index是long类型,即使100万QPS的处理速度,也需要30万年才能用完。
- 每个生产者或者消费者线程,会先申请可以操作的元素在数组中的位置,申请到之后,直接在该位置写入或者读取数据。
回顾
Threadlocal的作用是
Threadlocal的原理是
Threadlocal 内存泄漏
Volatile 与synchronized区别是什么
什么是重排序
什么情况下重排序对程序有影响?
怎么保证线程可见性
并发队列的理解
非租塞队列和阻塞队列的区别
有界队列和无界队列的区别
Jdk的并发包
线程池有哪些分类
线程池实现原理 brolkingqueue
线程池配置多少合适?
threadpoolExecutor有哪些参数
你了解哪些锁
乐观锁和悲观锁有哪些区别
哪些原子类
原子类的原理你有过了解么
什么是CAS无锁机制 ---自旋锁
自旋锁和互斥锁区别---
什么是future模式
Callable与thread的区别
你了解哪些并发框架
如何检测死锁 jconsole
lock锁底层原理是什么
你有了解AQS嘛
Synchronized 底层实现原理
内存屏障是怎么回事?