多线程
1,synchronized原理
syn关联的是一个lock对象,lock为Monitor结构(JVM级,C++实现)含有三个属性:
1:WaitSet,关联的是等待(调用了wait等)的线程
2:EntryList,关联的是没有获取到锁的,阻塞争抢锁的释放
3:Owner,获取到锁的线程
2,Java中synchronized的三种形式
有偏向锁,轻量级锁,重量级锁,分别对应锁只能被一个线程持有,不同线程交替持有,多线程竞争,具体使用哪种锁有JVM决定。
1,重量级锁:底层使用Monitor实现,涉及用户态和内核态切换,进行上下文切换,,成本较高,性能较低
2,轻量级锁,线程加锁的时间是错开的(无竞争),就可以使用轻量级锁,轻量级锁修改了对象头的锁标志,相对重量级性能提升很多,每次修改都是CAS操作,保证原子性,
3,偏向锁,一段长时间只被一个线程使用锁,就可以使用偏向锁,在第一次得到锁会有一个CAS操作,之后该线程再获取锁,只需要判断Mark word中是否是自己线程id即可,而不用开销较大的CAS命令,该锁jdk17默认禁用21移除了
3,关键字volatile
volatile 是轻量级线程间可见性保证,类似“告示牌”,写操作一个变量时会把数据写到公告牌(主内存),读操作:必须去读公告牌(主内存)中的数据,但不能保证原子性,复杂的操作仍需加锁
还可禁止进行指令重排序,volatile 通过在读写操作前后插入特定的内存屏障,阻止特定方向的指令重排序:volatile 写之前的代码不能重排到之后,volatile 读之后的代码不能重排到之前,从而保证程序的有序性
4,什么是AQS,CAS
AQS是多线程中队列同步器。是一种锁机制,作为一个基础框架使用
AQS内部维护一个先进先出队列,存储着排队的线程,队列中有一个线程将属性修改为1,着代表该线程获得资源
CAS是比较交换,无锁算法,乐观锁
5,ReentrantLock锁
是一个可重入互斥锁,更强大更灵活的锁。可重入性:同一线程可多次获取一把锁不会导致死锁,每次获取锁计数器+1释放就-1到0时才真正释放。
支持公平锁和非公平锁,可中断超时获取多个条件,显示获取释放锁等
实现原理:主要利用CAS+AQS队列实现。。必须在finallay中释放防止死锁
6,ConcurrentHsahMap
jdk1.7采用的是一个固定大小的Segment的数组大小为16不可扩容,每一个数组都指向另外一段数组,用的是ReentrantLock锁住Segment中的元素
jdk1.8和hashMap同样的底层采用CAS添加新节点,采用synchronized锁定链表或红黑树的首节点,相对于1.7颗粒度更细,性能更好
7,线程池中常见的阻塞队列
1,LinkedBlockingQueue:默认无界支持有界,底层是链表,两把锁(头尾)场景:固定线程数任务量平稳
2,ArrayBlockingQueue: 强制有界,底层数组,一把锁锁住整个(全局锁)场景:内存敏感需严格限流
3,SynchronousQueue: 略,场景:突发流量,任务执行快。原因:无缓冲直接创建线程
4,DelayedWorkQueue:略,场景:定时/周期性任务。原因:堆排序+延迟获取
5,PriorityBlockingQueue:略,场景:任务有优先级
8,如何确定核心线程数
高并发,任务执行时间短:cpu核数+1
并发不高,任务时间短:1,IO密集型任务:cup*2+1 。。2计算密集:cpu数+1
9,CountDownLatch
是一个“控制器” , 控制某些线程结束后再能往下执行。指定门阀数(计数值)后,在其他线程中末加上.countDown()代表门阀数减一,直到=0才能执行.await()下面的代码
10,Future
可以看作是一个工具类,可以让某个线程先跑着,等待.get()阻塞取出线程结果,可放入多个不限定类型的线程
11,并发量控制:Semaphore类
s=new Semaphore(3)设置三个通行证,s.acquire()申请通行证。s.release()归还。获得通行证才能执行
12,ThreadLocal
本地线程即线程拥有自己的独立资源供自己存取,线程安全
每个线程内都有TheadLocalMap的成员变量,key是弱引用,value是强引用,可能会导致无法回收,内存泄漏
调用set以ThreadLocal自己为key,资源为value存入当前线程的Map中。
get也是以自己为为key,查去线程中的资源
remove也是以自己为key,删除资源,避免内存泄漏
常用场景:不同页面用户的信息存取
13,线程基础
线程与进程区别:操作系统分配资源的基本单位,线程存在于进程,是CPU调度的基本单位
实现线程方式:1,继承Thread 2,实现Runnable(无返不能抛) 3,实现Callable(带返回,能抛异常)
线程6中状态:新建,可运行,阻塞,等待,超时等待,终止
14,线程池
很不建议用Executors创建线程池,会导致线程池队伍无限大OOM风险,必须手动new ThreadPoolExector创建,
为什么用?避免频繁创建销毁,控制并发量,统一管理
七大参数:1-核心线程数 2-最大线程数 3-非核心空闲时间 4-时间单位 5-任务队列 6-线程工厂(起名用) 7-拒绝策略
线程执行流程:1-任务进来->核心线程未满->创建核心线程
2-核心满了->进入队列
3-队列满了->创建非核心线程
4-总线程也满了->拒绝策略
15,死锁的4个必要条件
互斥,不可剥夺,请求保持,循环等待。缺一不可
故解决死锁破环任一条件即可,常用:按顺序加锁,设置超时,避免循环等待
16,其他
线程安全三要素?? 原子性,可见性,有序性
synchronized能保证什么?? 以上3点都能保证
volatile能保证什么?? 可见性,有序性,不能保证原子性
浙公网安备 33010602011771号