并发模型第一章
并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力。
第一天:内存和互斥模型
1.竞态条件和内存可见性(要保持内存可见性,就得保证同时是同步的)--但是效率低下,大量线程同时会阻塞按照
2.多把锁:哲学家进餐,先左手后右手很有可能出现死锁问题,一个线程想要使用多把锁就要考虑死锁,所以哲学家进餐只要保证左右都拿起即可,不要先左右,只要保证筷子的 编号是全局唯一且有顺序即可
就是按照约定的全局的顺序去获取多把锁,调用外星方法(保护性加锁复制)
长时间的持有锁可能会导致思索的发生,并且影响程序的并发度
java的乱序执行:编译器的静态优化,jvm的动态优化,硬件通过乱序执行的优化。
第二天 超越内置锁
终止死锁的唯一方法就是终止jvm,内置锁无法设置超市,且线程设置好内置锁无法进入主色只好就无法中断该线程
java join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行。
超时锁:synchronized 是非公平锁,也就是说每当锁匙放的时候,所有等待锁的线程并不会按照排队顺去依次获得锁,而是会再次去争抢锁。
ReentrantLock 相比较而言更为灵活,它能够支持公平和非公平锁两种形式。只需要在声明的时候传入 true。
trylock()在获取锁失败以后可以有超所机制,避免了无尽的死锁但不能避免死锁。特别是在所有死锁进程通知超时的时候
交替锁 只锁住进程的一部分,其他地方可以自由访问例如链表的顺序问题,总是按照全局的固定的顺序去获取多把锁
try(){
while)(!条件为真){
condition.await();//Condition是要和Lock配合使用的也就是Condition和Lock是绑定在一
<使用共享资源>
}
finally{lock.unlock();}
}//等待的条件为真,线程解锁继续执行,条件不为真,线程调用await();
调用await(),原子的恢复运行并重新加锁,即解锁并阻塞等待该条件的发安生.
在解决哲学家进餐问题的时候,由两把锁换成了一把锁更好,更好的提高了并发度,之前是一个哲学家拿起筷子等待别人,现在是哲学家理论上可以进餐时那么他就可以进餐
通过使用原子变量来避免锁的使用,只有是原子操作的 volatile 变量才是线程安全的。
内置锁(synchronized)非公平锁,关键字不能继承。内置锁是可重入锁。效率较低是因为:
锁的对象就是调用该方法的对象。但是修饰方法会比修饰代码块的执行效率低,因为方法的创建与销毁都是需要耗时的,修饰在方法上,方法的创建与销毁时也都是占用锁的,导致了不必要的浪费。
课后思考:
- 读写锁ReentrantReadWriteLock,它表示两个锁,一个是读操作相关的锁,称为共享锁;一个是写相关的锁,称为排他锁,描述如下:
线程进入读锁的前提条件:
(1)没有其他线程的写锁,
(2)没有写请求或者有写请求,但调用线程和持有锁的线程是同一个。
-
什么是假唤醒
当一个条件满足时,很多线程都被唤醒了,但是只有其中部分是有用的唤醒,其它的唤醒都是无用功
1.比如说买货,如果商品本来没有货物,突然进了一件商品,这是所有的线程都被唤醒了 ,但是只能一个人买,所以其他人都是假唤醒,获取不到对象的锁