多线程并发编程中的锁

  • Post author:
  • Post category:其他


1、volatile,修饰的a在1线程执行完后,写回内存刷新了,此时缓存行中的线程2所用的a就被标记为无效了,要再次从内存读取,线程1刷新以后的a。但是他只能保证当前查看的时候是正确的,但是最后的结果是不保证的


总线是传送地址和数据,要先传地址再传数据

,这时就将缓存行中的地址也发送出去,而另外的地址就标记为无效

2、

缓存一致性机制

会阻止同时修改由两个以上处理器缓存的内存区域数据,也就是避免同时两个刷新回写到内存。

volatile保证最先刷新回内存的是有效的。之后的是无效的

3、线程执行方法相当于拷贝方法,synchronized不能锁住变量只能锁住方法,synchronized锁住的静态方法,是锁住的类

4、(重要面试点)类锁:

如果有N个静态方法,加锁了,有一个线程执行了其中一个加锁的静态方法,这个类中的其他加锁的静态方法就不能执行,直到被执行的那个方法结束执行,其他方法才可以被执行,其他不加锁的方法不受影响。这就是类锁。

5、(重要面试点)对象锁

对非静态的方法加锁,在其他类中创建这个类一个对象,用这个对象调用加锁的非静态方法,也是执行一个方法后加锁的其他方法就无法执行,直到执行的方法执行结束,才可以执行。

6、类锁和对象锁是互不干扰的

类锁是在堆中加锁,对象锁对栈中的对象加锁,当他们被调用的时候,是互相不干扰的。

加锁的不影响不加锁的

7、主线程中的优先级是比其他线程高的。

8、t1.join();意味着线程t1执行完成之后,后面的代码才执行

9、在没有锁机制的情况下,两个线程执行加加操作,得到的最终结果是错误的。

出现这一情况的原因是,读写顺序问题,所有的并发编程问题,都是要保证写后读,才能计算成功。

10、如何判断一个锁什么时候释放完成:

①方法执行完;②同步方法块执行完;③产生异常也会释放锁

11、同步是线程排着队一个一个地执行

12、Monitor表示一个同步方法块的执行边界

13、每个对象当中都有记录类的地址,也就是自己的所属类型

14、java对象头存储结构:32bit

25bit 的对象hashCode;4bit的对象分代年龄;1bit的是否偏离;2bit锁标记位;

4bit对象分代年龄,表示只能迭代15次,进行多少次垃圾回收

15、锁状态:

无锁、偏向锁、轻量级锁、重量级锁

锁状态 轻量级锁 重量级锁
优点 自旋不断去试探,反应快。只要释放资源就可以被获得 CPU浪费不严重,能让CPU全力去执行整个任务,在高并发的情况下,重量级锁的效率最高,当一个线程拥有锁以后,其他线程就会进入阻塞队列,不消耗CPU,仅仅在通知的时候会消耗少许CPU算力。
缺点 自选代价就是CPU消耗极大,当要执行的线程很多的时候,多线程自旋对整个任务的效率影响很大 线程之间有通知会导致线程反应慢

16、锁的升级

synchronized—-》偏向锁—》轻量级锁—-》重量级锁     并且锁的状态是不可逆的。

偏向锁是没有竞争;轻量级锁是竞争少的个位数竞争;重量级锁是竞争两位数以上的。

17、CAS 比较并且替换(面试重点)

不使用锁,达到上锁的目的

a=0,v=0;第一个首先读取,并修改a=3,v=1,然后


观察期望值v是否为0


,如果是,说明没有被修改过,则可以改回。第二个线程读取a=3,v=1;进行修改a=7,v=2;


此时观察期望值是否是1


,如果是则可以写回,否则就要重新读取

18、ABA问题:


不加信号量,单纯只比较期望值


,A不能察觉出B已经修改过了,但是又把a改成了0,能够让A接着读取。虽然现在并不影响计算结果,但是在某些环境下是有影响的。

B已经修改过,但是修改过的值依然是A的期望值,A就察觉不出来



版权声明:本文为qq_61353850原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。