1 CAS
- 乐观锁,先修改数据再比较并交换。
- 自旋锁,不断循环获取锁,消耗CPU
- 对比Synchronized,ReentrantLock性能更高。
- ABA问题,只关心结果。添加版本号解决。
2. ThreadLocal的底层原理
- ThreadLocal线程本地存储机制,能把数据缓存再某一个线程内,该线程可以在任意时刻,方法中获取缓存的数据。
- ThreadLocal底层是通过ThreadLocalMap来实现,在Thread对象中存在一个ThreadLocalMap,key->ThreadLocal对象,value->需要缓存的值
- 使用不当会造成内存溢出。使用后,需要手动remove ThreadLocalMap对应的Entry对象。
- ThreadLocal 应用场景-事务,数据库连接。(一个线程持有一个连接)
3 Synchrouozed和ReentranWriteReadLock的区别?
- synchronized-关键词;ReentrantLock-类
- synchronized-jvm实现;ReentranLock-API实现
- synchronized-自动加解锁;ReentranLock-手动加解锁。
- synchronized-非公平锁;ReentranLock-可公平/非公平锁。
- synchronized-锁信息存在对象头;ReentranLock-锁中的state表示锁的标识。
- synchronized底层有一个锁升级的过程。
4 线程有哪些状态?
- 新建
- 就绪。Thread.start()
- 运行
- 阻塞
- 等待。Object.wait()
- 超时等待.超时自动返回
-
死亡
image.png
5 新开线程的三种方式?
- Runnable接口
- Thread类
- Callable
- 线程池
6 Volatile为什么不能保证原子性?
- 保证可见性
- 禁止指令重排(执行顺序不变)
- 不保证原子性
7 ConcurrentHashMap底层实现原理?
jdk1.7 数组+链式存储
jdk1.8 数组+链表+红黑树
8 并发,并行,串行 区别?
- 串行:线程排队执行。
- 并行:2个任务同时执行。
- 并发:2个任务看着是一起执行,由CPU切换执行线程1一部分,再切换上下文执行线程2一部分,来回切换,看着是一起执行。
9 死锁如何避免?
造成死锁的4个要素:
1.一个资源每次只能被一个线程使用。
- 一个线程阻塞等待资源时,不释放已占有资源。
- 一个线程获取资源,且未使用完前,不能被强行剥夺。
- 若干线程头尾相接在等待资源。
只要破坏以上4个要素之一即可。 - 加锁顺序。保持统一顺序。
- 加锁时间。超时时间。
- 死锁检查。
10 线程池的底层工作原理?
- 线程数量<corePoolSize,即使线程池的线程处于空闲,也创建新线程处理。
- 线程数量>=corePoolSize,缓冲队列workQueue未满,那么任务放到缓冲队列中。
- 如果无法加入workQueue,且线程数<maxPoolSize,创建新线程执行任务。
如果线程数>=maxPoolSize,拒绝执行策略。
11 ConcurrentHashMap扩容?
jdk1.7 基于segment分片实现。segment也是新增数组拷贝。
jdk1.8 多线程同时扩容,先生成新的数组。每一个线程分组转移数组。
12 synchronized偏向锁,轻量锁,重量锁,自旋锁
1.偏向锁:线程获取对象锁后,会把线程id存到对象头,下次可以直接获取
2.轻量级:线程a获取对象锁后,线程b等待获取对象锁。此时偏向锁升级为轻量级锁。不阻塞,自旋。
3.重量级:在轻量级锁的基础上,不断自旋,但却无法竞争到锁,升级成重量级锁。
4.自旋锁,不阻塞,通过CAS乐观锁,不断循环获取预期的标记,若获取了则也获取到锁。
13 sleep,wait,join,yield的区别?
- sleep,Thread静态方法,不释放锁,释放cpu的执行权。
- wait,Object方法,释放锁,进去等待池,需要被唤醒。
- join,在B线程执行A.join(),B进入阻塞状态,等待A的结束。
- yield,释放cpu的执行权,之后重新竞争cpu执行权。
14 AQS的理解?
- AbstractQueuedSynchronizer,抽象队列同步器
- AQS是java线程同步的组件,是jdk很多锁工具的核心实现组件。
- AQS维护了一个信号量state和一个线程组成的双向队列。
线程队列-排队,信号量-红绿灯,控制线程的执行和阻塞。 - 在可重入锁的场景下,state表示加锁的次数,0表示无锁,加锁+1,释放锁-1.
网友评论