线程安全问题
核心思想:上锁
有线程安全性问题的代码才需要上锁,怎样才会出现线程安全问题?修改对象就会出现。
jvm中,多个线程竞争一把锁,最终只有一个能抢到,抢不到的中间需要经历锁升级的过程,如果一直没获取到锁就会一直阻塞等待。
解决线程安全问题方法:
1.使用synchronized锁,1.6之后锁的升级过程,偏向锁-轻量级锁-重量级锁
2.使用Lock锁,需要自己实现锁升级,AQS+CAS
3.使用ThreadLocal,注意内存泄漏问题,需要手动remove。
4.原子类CAS非阻塞式。
synchronized锁的用法:
1.修饰代码块,指定加锁对象
2.修饰实例方法,作用于当前实例加锁
3.修饰静态方法,作用于当前类对象加锁
synchronuzed加在实例方法 上和使用代码块用的都是this锁,
加在静态方法上就是类锁
锁之间的通讯
wait(),notify(),需要放到sync代码块中使用。
如何设置线程执行顺序,可以使用Join(本质还是使用wait notify)
yield:主动释放cpu执行权,让线程从运行状态到就绪状态,让其他线程执行,底层是操作系统的调度器。
wait和sleep区别:
sleep是Thread类的,wait是Object类的。
sleep不释放锁(抱着锁睡觉),wait释放对象锁(sync的this锁)所以必须在sync中使用,而sleep不释放锁,所以在哪都可以使用。
wait和notify可能会出现虚假唤醒的问题,所以sync中出现if判断的话容易出问题,需要改成while循环使用
@Async注解
spring提供此注解以供异步使用,但是可能会失效,所以需要专门写一个异步类编写async方法,然后其他地方通过autowired去引用使用。
注意:这个注解相当于new Thread,每次调用都会创建新的线程,所以最好结合线程池使用。
整合线程池:
使用:
Lock
ReenTrantLock 默认非公平锁
与synchronized区别:
1.sync无法获取锁状态,lock可以判断是否获取到锁
2.sync自动释放锁,lock必须要手动释放,不释放就死锁
3.sync获取锁,会一直阻塞,lock不一定会一直等待
4.sync可重入,非公平,不可中断,lock可重入,非公平(可以设置成公平),可中断
5.sync适合少量代码块,lock适合大量代码