1.Future模式
这里从Future模式切入,讲了一些关于多线程的知识:
在跑多线程的时候,假如有2个子线程,那么把其中一个子线程threadA的结果提前写好,写给需要用的threadB
这样,就不需要使用synchronized锁的notify和wait来阻塞线程了,这里的阻塞就是指的阻塞主线程,否则这里要等threadA执行完了,拿到结果才给threadB
2.callable接口
上面的Future模式,就是用到了callable接口,这个接口跟run重写开子线程有不一样的地方就是,有回调,所以可以实现Future模式,而重写run方法是不行的
3.submit创建线程池
使用submit创建线程池,与execute比较,submit会返回一个bool值,来判断是否创建成功
这里有一点要注意,多线程是不能断点调试的,因为每次cpu分配的资源不一样
4.CAS无锁机制
CAS无锁机制的底层,其实就是不停的读当前值是否跟之前的有改变,每次操作之前就判断一下,与上次是否相同,不同的话,就再刷新拿值,底层实现原理其实是没有用到锁
compare and swap 比较再交换
5.CAS无锁机制里面包含3个参数:
1.V=需要更新的变量 主内存
2.E=期望值(预期值) 本地内存
3.N=新值
V=E,说明变量没有被修改过,这个时候会把V值设为N
如果V != E,说明变量已经被修改
如果发现已经改变,那么就把主内存的值刷新到本地内存中
然后再进行比较
缺点:
ABA问题:
2次修改变回原来的值怎么办,这里应该是可以用ver版本号来解决
5.重入锁
重入锁,就跟上次总结了一样,如果一个func拿到了锁,那么即使再次碰到同样的这个锁,也是被锁一次,而不是2次,但是切记是同一把锁
6.volatile
这里需要注意点的是,volatile不具备原子性,也不具备线程安全,但是可以防止重排序,其具有可见性,在后面说道的双重验证锁的时候,有用到
7.乐观锁&悲观锁
乐观锁:
就是CAS这种,不停的去读数据,判断是否为新值,这里底层的原理,之前讲过,但是忘记了,这个并不是很重要,一般情况下,都会有一个自增的version版本号,通过这个来解决线程安全问题
悲观锁:
真正的锁,会阻塞,来保证线程安全
8.AtomicInteger
这是一个比较特殊的原子数的类,只需要知道其底层用到的是乐观锁
9.自旋锁 & 互斥锁
自旋锁在没有获得锁的时候,这个时候会一直循环的尝试取锁,而互斥锁会进入休眠
所以说,如果是自旋锁,那么其会一直处于busy-waiting状态,是不是有点耗资源呢
10.公平锁 & 非公平锁
顾名思义,一个是按顺序拿锁,一个不是
11.插几句小知识
下一次写android,可以用一下XUtils这个第三方的异步的一个类
如何检测死锁.
jconsole工具
12.Disruptor
Disruptor听说是比较牛逼的用CAS无锁机制搞的一个框架,目测对服务器性能要求很高
使用到了一个叫做ringBuffer的数组,环形数组的大小必须是2的n次方
使用ringBuffer可以把Msg主动推给消费者,而不是消费者主动取
disruptor框架创建:
1.创建可以缓存的线程池executor
2.创建工厂EventFactory<longEvent>
3.创建一个ringBuffer大小,2的n次方
4.创建Disruptor对象
5.连接消费者 / 注册消费者:disruptor.handleEventsWith
6.启动disruptor: .start()
7.获取ringBuffer容器
8.创建生产者producer
9.指定缓冲区的大小byteBuffer
10.把线程池和disruptor关闭
总结:
关于java的锁,到目前为止先到这里,下面学习主要的设计模式