java并发编程知识梳理

1.如何实现处理线程的返回值  

(1)主线程等待法

(2)join(),t.jpin()会阻塞主线程,直到t执行完

(3)通过Callable接口实现,通过FutureTask或线程池获取 

2.线程的生命周期/状态

(1)新建New:新创建的线程还未执行

(2)可执行Runnable:执行状态,或者可执行状态

(3)有限期/无限期等待Wating:Thread.join(),t.wait()等触发,该状态不会被分配cpu执行,需要被显式唤醒(Noticify/NoticifyAll)/到期自动唤醒(在wait或join方法设置过期时间)

(4)阻塞Blocked:阻塞状态,原因可能是等待排它锁,或者调用sleep()

(5)销毁Terminated:线程终止执行

3.sleep和wait方法的区别

(1)sleep是Thread类的方法,wait是Object类的方法

(2)sleep可以在任何地方使用,wait必须在synchronized方法或代码块里使用

(3)sleep使线程进入阻塞状态,会释放cpu资源但不会释放同步锁,而wait使线程进入wait状态,会释放CPU并释放同步锁对象

4.notify和notifyall的区别

notify:随机选中等待池中的一个线程,进入锁池去竞争锁(竞争到锁则变为Runable状态,竞争不到锁,则变成Blocked状态)

notifyall:使等待池中所有线程进入等待池去竞争锁

5.线程的常用方法

yield:暗示当前线程可以让出cpu,具体是否出让cpu则由系统决定,yield即使让出cpu也不会释放同步锁

interrupt:暗示当前线程可以被中断,具体是否中断由系统决定,如果线程处于阻塞状态,则立即抛出interruptException异常;如果线程处于正常运行状态时,调用interrupt方法只是会给线程的interrupt标志置为true,业务代码可以根据interrupt标志执行业务逻辑

6.什么是锁的重入

如果synchronized锁的同一个对象,则可以在已经拿到synchronized的线程的代码块里继续对该对象加锁

7.自旋锁和自适应自旋锁

自旋锁:区别于synchronized的悲观锁,自旋锁由开发人员实现,通常是写一个while循环判断其他线程某一变量,达成条件则继续执行,同时为避免死锁,会设定一个自旋次数作为跳出条件

自适应自旋锁:原理同自旋锁,不在写死固定的自旋次数条件,让自旋更“智能”话,具体的自旋次数会结合上一次自旋所花费时间和目标线程的状态,动态设置

8.synchronized锁的四种状态

无锁:未加锁

偏向锁:不阻塞,当大多是时候,不存在线程竞争(指虽然代码加了锁,但实际运行时基本都是单线程在调用)时的状态,偏向锁状态会给频繁占用锁的线程贴个“默认”标识,然后当线程访问锁时,如果判断是被“默认”标识的线程,则不会再进行竞争判断锁等逻辑,直接获取锁,节省开销

轻量级锁:不阻塞,原理同轻量级锁,加锁线程数增加为2个,即2个线程频繁交替执行的场景

重量级锁:阻塞,适用3个或3个以上线程竞争锁的场景

8.synchronized锁的内存语义

当线程释放锁时,会将线程本地内存的共享变量刷新回主内存

当线程获取锁时,会将线程本地内存的共享变量置为无效,再去主内存中读取最新值

9.synchronized和reentrantLock的区别

(1)synchronized是关键字,reentrantLock是juc包下的类

(2)synchronized不能实现线程公平,reentrantLock可以通过new ReentrantLock(true);的方式实现线程的公平(即最先进入锁池的线程,当锁被释放时最先获取锁)

(3)reentrantLock可以对锁设置等待时间,避免死锁

(4)reentrantLock可以获取各种锁的信息

(5)机制上ynchronized是操作判断mark word,reentrantLock是调用Unsafe类的park()方法

10.jmm中各数据类型的存储方式和操作方式总结

主内存:引用类型共享变量的实例,成员变量,static变量,类信息

本地内存:引用类型共享变量的引用,基本类型,本地变量

11.volatile的两个作用

1.通过插入内存屏障保证变量的内存可见性

2.禁止cpu指令从排序

 上图中,需要用volatile修饰instance

12.CAS及其ABA问题

cas即乐观锁的实现思想,在juc的atomic包中有很多线程安全类都是基于乐观锁实现的

ABA问题:如果线程AB并发修改同一共享变量,且B在A执行期间,修改了多次但结果值没变(例如由0改为1,又改为0),则线程A执行修改时,不会认为该变量被修改过.此问题在CAS中以通过添加版本号解决

13.synchronized的锁消除和锁粗化

jvm会根据代码写法在程序执行时优化synchronized修饰的范围以提升代码性能,以StringBuffer为例(StringBuffer的append方法是synchronized修饰的)

(1)锁消除:如果某StringBuffer对象是方法内的局部变量,则即使调用append方法,jvm也不会执行同步判断,因为这种情况不可能存在线程安全问题。

(2)锁粗化:如果StringBuffer对象是方法参数,该方法内循环执行了append,则jvm会在循环外层加锁,而不会每次append都做加锁解锁操作

14.安全发布对象的四种方式

(1)在静态初始化函数中初始化一个对象引用(如private static Helper helper = new Helper())
(2)将对象的引用保存到volatile类型的域或者AtomicReferance对象中(利用volatile happen-before规则)
(3)将对象的引用保存到某个正确构造对象的final类型域中(初始化安全性)
(4)将对象的引用保存到一个由锁保护的域中(读写都上锁)

15.线程安全的单例

(1)饿汉单例

(2)懒汉单例:如果sync加载方法上,线程安全,如果用双重检查注意要结合volatile来禁止cpu重排序

(3)枚举单例:由jvm保证只创建一次,推荐使用

 16.一些常用容器的普通版,同步版,并发版

普通版同步版并发版
ArrayListVector

CopyOnWriteArrayList

HashSetCopyOnWriteArraySet
TreeSetConcurrentSkipListSet
HashMapConcurrentHashMap
TreeMapConcurrentSkipListMap

17.同步容器一定线程安全么?

不是的,虽然在同一个方法中有synchronized修饰,但是不同方法操作同一对象时还是会有问题,比如一个线程不停调用Vector对象的remove方法,另一个线程不停的调用get方法,就可能造成get时数组下标越界(因为已经被remove),所以使用同步容器时必须要注意代码的写法

18.各种atomicXXX类的写方法为什么线程安全?

各种atomic下的类应用了CAS(CompareAndSwap)原理实现内存可见,即在写之前对比当前值和内存中最新值是否一致,不一致则不写,具体实现是通过Unsafe类的CompareAndSwapXXX方法(native方法)获取的。同时通过自旋实现原子性

19.LongAdder和AtomicLong的区别(Double也一样)

LongAdder在计算时是把long本身分成多个热点数据Cell,分别计算结果后再求和返回,在高并发场景下性能优于AtomicLong,而在类似序列号这种要求计算准确的变量时,或者并发度较低时,AtomicLong更合适性能更佳

20.线程池参数

(1)corePoolSsize:核心线程数

(2)maximumPoolSize:最大线程数

(3)workQueue:等待执行任务的阻塞队列

以上三个参数是线程池调优的核心,工作流程如图

简单一句话:提交任务,线程池中的线程数可以增长至corePoolSize,之后继续提交任务将暂存至队列中,如果队列满,则看是否能继续增长线程数至maximumPoolSize,超出后将进行拒绝策略处理。显然,如果采用×××队列,那么maximumPoolSize将失效,线程池中的线程最多就是corePoolSize个线程工作。

21.java中的死锁和活锁

(1)死锁:两个线程互相等待对方释放锁才能继续执行(如线程1获得A锁,需要获得B锁才能继续执行,线程2获得了B锁,需要获得A锁才能继续执行)
(2)活锁:两个线程互相改变了对方的执行完成条件,导致谁也无法执行完成(比如线程1需要a=0执行完成,线程2需要a=100执行完成,两个线程一个不断a++,一个不断a--,导致a一直在0~100之间)

22.本地模拟一个并发场景

用countDownLatch或者CyclicBarrier

countDownLatch:在并发编程中有两个作用,“计数器”和“信号枪”,模拟并发主要是应用其“信号枪”原理,即在所有线程都达到某一条件(计数器为0时)同时执行。具体做法是在线程代码中添加countDownLatch对象的await方法使线程阻塞,在线程达成某条件时调用countDownLatch对象的countDown()方法使计数器-1

代码示例

原理如图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值