1.多线程一定好么?
cpu密集不好 io密集好
2.如何减少上下文切换:
无锁并发(数据id根据Hash分段)、CAS、最少线程
3.java线程避免死锁:
避免一个线程同时有多个锁
避免一个锁占用多个资源
lock.tryLock代替内部锁
内存屏障:限制命令操作顺序,有LoadLoad、LoadStore、LoadStore、StroreStreo四种屏障
缓冲行:cpu缓存最小储存单位
写命中:缓存有,直接写入缓存
缓存一致性:主存改变,其他缓存改变(read、load、use绑定)
顺序一致性:单个线程内执行结果一定是不变的(但依然有指令重排,只是结果不受影响的重排)
4.八个CPU原子命令:
lock、unlock、read、load、use、assign、store、write
5.volatile做的事:
1.lock前缀指令使缓存行立即写入内存(assign、store、write绑定)
2.其他cpu缓存无效
3.加入内存屏障
使用前景:不依赖于上次数据
使用案例:i++:tmp = i;tmp=tmp+1;i = tmp;
64位机器跑32位jvm,long和double:2段分2次计算,不加volatile会导致结果前32位是一个线程结果,后32位一个线程结果
6.synchronized
对象加锁,Monitor对象,monitorenter和monitorexit命令实现锁升级
7.ReentrantLock 可重入锁
通过CVS等实现,比synchronized效率略高,有公平锁非公平锁
锁可多次进入,并把拥有数++
lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
8.ReentrantReadWriteLock
read/write两把锁
写锁与ReetrantLock类似,只有写锁读锁都没被占用才获得锁
读锁拥有数是多个线程的,每个线程拥有数只能自己通过ThreadLocal记录
写锁结束降级读锁,避免可见性问题
9.Lock和synchronized区别
Lock是通过代码级实现,cvs
synchronized是通过jvm的monitor实现的
还多了 锁投票,定时锁等候和中断锁等候等特性
使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
10.AQS(AbstractQueuedSynchronized)
有队列,有state、进入会先自旋再阻塞,默认非公平,队列唤醒了调用tryAcquire,不一定能获取锁
11.java对象头:
MarkWord 长度:32/64,存储hashCode或者锁信息
12.CAS unsafe.compareAndSwap(对象地址,原来值,要修改值)
unsafe是通过操作系统实现(CMPXCHG指令),如果失败返回false;
13.CAS使用:自旋锁、自适应自旋锁
14.锁的升级
偏向锁(markword指向所在线程,代价低,两个线程则停安全点撤销)->轻量级线程(markword置换到拥有者线程,线程对象互指。两个线程则b线程自旋等待)->重量级锁(syn、reeentrantLock)
比较:
偏向锁: 加锁解锁消耗极少,锁竞争的安全点带来消耗。 适用于一个线程
轻量级锁:响应快,自旋消耗cpu 追求响应时间,同步块非常快
重量级: 追求吞吐量,同步块执行时间长
15.处理器实现原子性策略:
LOCK#信号是一个线程独占共享内存(通过锁住主内存总线,之后优化成缓存锁)
缓存锁保证原子性
16.java原子实现:
锁和CAS
CAS局限性:ABA问题(过程无感知)、循环时间开销大、一次保证一个变量
17.内存模型(对底层抽象)
线程通信方式:
内存模型(共享内存)
消息传递(A复制到主内存,再从主内存写到B)
管道:输入流输出流(PipedReader,PipedWriter,PipedInputstream,PipedOutputStream)
内存模型:本地内存(共享变量副本、局部变量)、主内存(共享变量)
指令重排序:编译优化重排、并行重排、内存重排
18.final域重写规则
构造函数内,final写入与被构造的对象引用赋值不能重排序(obj=this会引发逃逸,例如此时别的线程调用obj.i,final的i变量还没初始化)
初次读含final域对象与随后读final区域不能重排
19.单例模式问题
实例化分为:1.开辟空间memory 2.初始化对象 3.设置instance指向memory。
指令重排可能是:1->3->2 , 若2还未执行,B线程认为instance非空,直接调用instance,导致错误
解决方案:1.volatile禁止重排序 2.匿名内部类(连自己加锁都不用,类自带实例化锁)
20.为什么使用多线程
1.多处理器发挥功效
2.更快相应,一个下订单带来一系列操作如何快速成功:线程派发,分任务执行
21.java优先级
不一定有用,主要是靠操作系统底层实现
22.interrupt
interrupt不会真的终止,只是一种协作机制
interrupt()将会设置该线程的中断状态位,即设置为true
使用Thread.currentThread().isInterrupted()方法(因为它将线程中断标示位设置为true后,不会立刻清除中断标示位,即不会将中断标设置为false)
thread.interrupted()(该方法调用后会将中断标示位清除,即重新设置为false)
一个线程处于了等待状态(thread.sleep、thread.join、thread.wait),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法调用处抛出InterruptedException异常,并且在抛出异常后立即将线程的中断标示位清除,即重新设置为false。抛出异常是为了线程从阻塞状态醒过来,并在结束线程前让程序员有足够的时间来处理中断请求。
锁的情况下不会被中断影响
23.阻塞状态与等待区别
阻塞是进锁里,等待是wait、sleep。sleep设置时间状态叫做超时等待状态
cpu密集不好 io密集好
2.如何减少上下文切换:
无锁并发(数据id根据Hash分段)、CAS、最少线程
3.java线程避免死锁:
避免一个线程同时有多个锁
避免一个锁占用多个资源
lock.tryLock代替内部锁
内存屏障:限制命令操作顺序,有LoadLoad、LoadStore、LoadStore、StroreStreo四种屏障
缓冲行:cpu缓存最小储存单位
写命中:缓存有,直接写入缓存
缓存一致性:主存改变,其他缓存改变(read、load、use绑定)
顺序一致性:单个线程内执行结果一定是不变的(但依然有指令重排,只是结果不受影响的重排)
4.八个CPU原子命令:
lock、unlock、read、load、use、assign、store、write
5.volatile做的事:
1.lock前缀指令使缓存行立即写入内存(assign、store、write绑定)
2.其他cpu缓存无效
3.加入内存屏障
使用前景:不依赖于上次数据
使用案例:i++:tmp = i;tmp=tmp+1;i = tmp;
64位机器跑32位jvm,long和double:2段分2次计算,不加volatile会导致结果前32位是一个线程结果,后32位一个线程结果
6.synchronized
对象加锁,Monitor对象,monitorenter和monitorexit命令实现锁升级
7.ReentrantLock 可重入锁
通过CVS等实现,比synchronized效率略高,有公平锁非公平锁
锁可多次进入,并把拥有数++
lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
8.ReentrantReadWriteLock
read/write两把锁
写锁与ReetrantLock类似,只有写锁读锁都没被占用才获得锁
读锁拥有数是多个线程的,每个线程拥有数只能自己通过ThreadLocal记录
写锁结束降级读锁,避免可见性问题
9.Lock和synchronized区别
Lock是通过代码级实现,cvs
synchronized是通过jvm的monitor实现的
还多了 锁投票,定时锁等候和中断锁等候等特性
使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
10.AQS(AbstractQueuedSynchronized)
有队列,有state、进入会先自旋再阻塞,默认非公平,队列唤醒了调用tryAcquire,不一定能获取锁
11.java对象头:
MarkWord 长度:32/64,存储hashCode或者锁信息
12.CAS unsafe.compareAndSwap(对象地址,原来值,要修改值)
unsafe是通过操作系统实现(CMPXCHG指令),如果失败返回false;
13.CAS使用:自旋锁、自适应自旋锁
14.锁的升级
偏向锁(markword指向所在线程,代价低,两个线程则停安全点撤销)->轻量级线程(markword置换到拥有者线程,线程对象互指。两个线程则b线程自旋等待)->重量级锁(syn、reeentrantLock)
比较:
偏向锁: 加锁解锁消耗极少,锁竞争的安全点带来消耗。 适用于一个线程
轻量级锁:响应快,自旋消耗cpu 追求响应时间,同步块非常快
重量级: 追求吞吐量,同步块执行时间长
15.处理器实现原子性策略:
LOCK#信号是一个线程独占共享内存(通过锁住主内存总线,之后优化成缓存锁)
缓存锁保证原子性
16.java原子实现:
锁和CAS
CAS局限性:ABA问题(过程无感知)、循环时间开销大、一次保证一个变量
17.内存模型(对底层抽象)
线程通信方式:
内存模型(共享内存)
消息传递(A复制到主内存,再从主内存写到B)
管道:输入流输出流(PipedReader,PipedWriter,PipedInputstream,PipedOutputStream)
内存模型:本地内存(共享变量副本、局部变量)、主内存(共享变量)
指令重排序:编译优化重排、并行重排、内存重排
18.final域重写规则
构造函数内,final写入与被构造的对象引用赋值不能重排序(obj=this会引发逃逸,例如此时别的线程调用obj.i,final的i变量还没初始化)
初次读含final域对象与随后读final区域不能重排
19.单例模式问题
实例化分为:1.开辟空间memory 2.初始化对象 3.设置instance指向memory。
指令重排可能是:1->3->2 , 若2还未执行,B线程认为instance非空,直接调用instance,导致错误
解决方案:1.volatile禁止重排序 2.匿名内部类(连自己加锁都不用,类自带实例化锁)
20.为什么使用多线程
1.多处理器发挥功效
2.更快相应,一个下订单带来一系列操作如何快速成功:线程派发,分任务执行
21.java优先级
不一定有用,主要是靠操作系统底层实现
22.interrupt
interrupt不会真的终止,只是一种协作机制
interrupt()将会设置该线程的中断状态位,即设置为true
使用Thread.currentThread().isInterrupted()方法(因为它将线程中断标示位设置为true后,不会立刻清除中断标示位,即不会将中断标设置为false)
thread.interrupted()(该方法调用后会将中断标示位清除,即重新设置为false)
一个线程处于了等待状态(thread.sleep、thread.join、thread.wait),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法调用处抛出InterruptedException异常,并且在抛出异常后立即将线程的中断标示位清除,即重新设置为false。抛出异常是为了线程从阻塞状态醒过来,并在结束线程前让程序员有足够的时间来处理中断请求。
锁的情况下不会被中断影响
23.阻塞状态与等待区别
阻塞是进锁里,等待是wait、sleep。sleep设置时间状态叫做超时等待状态