2021面试题
尚硅谷周阳 https://www.bilibili.com/video/BV1zb411M7NQ?p=1
视频很多,慢慢看吧,讲的还是很细,可以了解很多不知道的东西
1、volatile 轻量级的同步模型
可见性、不保证原子性、禁止指令重排序
多线程环境中可以用volatile避免指令重排
相当于内存屏障,指令前后cpu不能重排,刷出cpu缓存
cpu指令 storestore+storeload\loadload
使用场景:
最适用一个线程写,多个线程读的
单例private volatile static Singleton instace;不然容易出现指令重排,会有安全隐患
if(instance==null){
sychrized(class){
if(instance==null){
new instance();//不加volatile可能出现指令重排
}
}
|
new对象,分3步,分配内存,初始化对象,设置指针
指令重排只保证单线程串行安全
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
对变量的写操作不依赖于当前值。
该变量没有包含在具有其他变量的不变式中
2\
jmm java内存模型可见,原子,有序
3、cas
compareAndSet第一个是期望已经的值和真实值一样,那么修改为 第二个参数是打算修改成的值。
4、unsafe
native 、rt.jar
cas CPU并发原语,CPU原子指令,底层汇编
5、atomicInteger getAndINcrement
依靠cas指令原语,先主内存拷贝到程序内存,再比较cas 跟期望是否一致,一样的话,就设置值。否则循环继续循环。
6、
cas没用锁,synchrinized加锁了
cas思想,自旋
7、cas缺点
循环时间长,开销大;
只能保证一个共享遍历的原子操作
引出来ABA问题
8、ABA问题解决?
原子引用更新AtomicReference比较的是对象的地址
AtomicStampReference
9\arraylist1.2
初始化object[]空数组,扩容原来的一半
add没加锁,所以多线程concurrentmodificationException
vector1.0 add有锁synchroized
Collections.synchroziedList();
CopyOnWriteArrayList 高并发变量都需要volatile
ReentrantLock lock.lock() unlock()
HashSet->Collections.synchronizedSet->CopyOnWriteArraySet
CopyOnWriteArraySet使用CopyOnWriteArrayList
HashSet底层就是hashmap 16,0.75,add是map put(e,object())
ConcurrentHashMap
String str传参数时,不改变原有值
ReentrantLock默认非公平锁
公平锁按申请顺序获取锁
非公平锁有可能造成优先级翻转或者饥饿,有点吞吐量大
synchronized非公平锁
可重入锁也就递归锁,非公平 比如ReentrantLock synchronized,一个线程获得锁后,内层函数仍然获取该锁,外层已经有所后,内层自动获取锁,是同一把锁。作用防止死锁。
ReentrantLock 2个lock,2个unlock时 运行正常
自旋锁:尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,减少线程切换,但会消耗cpu。
自旋锁可以使用AtomicReference<Thread> compareAndSet实现自旋锁
ReentrantLock synchronized 独占锁
共享锁 ReentrantReadWriteLock,读读共享,读写写写独占
ReentrantReadWriteLock.readLock().lock()
CountDownLatch.countDown() CountDownLatch.await()
CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务
枚举jdk1.5 Enum.values()
在CyclicBarrier类的内部有一个计数器,每个线程在到达屏障点的时候都会调用await方法将自己阻塞,此时计数器会减1,当计数器减为0的时候所有因调用await方法而被阻塞的线程将被唤醒
CountDownLatch: 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。
CyclicBrrier: N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。
Semaphore用于共享资源的互斥,
Semaphore.acquire(); Semaphore.release();
Semaphore是一个计数信号量,常用于限制可以访问某些资源(物理或逻辑的)线程数目
ArrayListBlockingQueue是有界的,是一个有界缓存的等待队列
LinkedBlockingQueue是无界的,是一个无界缓存的等待队列,默认最大INterger..Max_value SynchronousQueue不存元素的队列,但是由于该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加。FIFO
priorityBlockingQUeue支持优先级无界队列
delayBlockingQUeue支持优先级延迟无界队列
linkedBlochingdeque链表双向阻塞对垒
会报异常:add IllegalStateException remove pelement队首
offer false、poll null没有时不报异常
put会等待队列有空余空间才放进去,否则一直等待.take也会等待
offer带时间时,不报错,返回false
https://blog.csdn.net/qq_42135428/article/details/80285737
https://blog.csdn.net/qq_42135428/article/details/80285737
https://blog.csdn.net/qq_42135428/article/details/80285737
阻塞队列:多线程领域
生产者消费者 while(){condition.await()} condition.signalAll();
ReentrantLock synchronized 区别:
1、synchronized关键字 通过monitor实现,monitorenter 2个monitorexit 异常正常退出
lock api层面的锁
2、自动、手动释放锁
3、synchronized不可中断,lock可中断 lockinterrputibly
4、加锁是否公平。synchronized非公平,ReentrantLock可选
5、是否绑定多个condition
synchronized没有,随机唤醒或者全部唤醒
ReentrantLock有多个唤醒,可以精确唤醒