Operation System: 多线程笔记

这篇文章主要记录一些关于多线程的比较零散的内容。


一、关于数据的可见性 & 内存屏障


根据内存模型,数据被某一个核所利用之后,会存在其cache甚至寄存器当中。当这段程序更新这个数据之后,未必马上写入内存。


此时,如果另一个线程(在另一个核上运行的内核态线程)读取这个数据,可能读到的还是旧的值。这时候,这个数据就是对另外的一个线程是不可见的。


那么,volatile关键词加在某个变量之前就是确保每次的更新都是马上更新到内存当中,使其对另一个线程可见。


volatile的实现原理是 memory barrier. memory barrier的底层原理是一条特殊的汇编指令。基本上它是一条这样的指令:a) 保证特定操作的执行顺序,以及 b) 影响某些数据(也许是某些指令的执行结果)的可见性。


1)指令排序参考:编译器和 CPU 能够重排序指令,保证最终相同的结果,并尝试优化性能。插入一条 Memory Barrier 会告诉 CPU 和编译器:在这条命令之前发生的必须待在这条命令之面,在这条命令之后的必须待在命令之后。


2)Memory Barrier(内存屏障)所做的另一件事是强制刷出各种 CPU cache(高速缓存)内容到内存——比如,一个 Write-Barrier(写入屏障)将刷出所有在 Barrier 之前写入 cache 的数据,因此,任何尝试去读这些数据的线程将会读到它们的最新版本,而不管线程在哪个 CPU 核心或者哪个 CPU 插槽(Socket)上执行。


如果你的字段是 volatile 的,Java 内存模型(Java Memory Model)会在你写入字段之后插进一个 Write-Barrier 指令,并且在你读这个字段之前插入一个 Read-Barrier 指令。由此可知,volatile确保读必须会发生在写之后。


除了volatile修饰变量实现可见性,也可以通过synchronized和lock来实现。synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。


二、原子操作


原子操作指的是利用一条汇编指令就能完成的操作。Java有专门的Atomic类来确保原子操作。譬如AtomicInteger类提供的atomic方法可以让这种操作具有原子性如getAndIncrement()方法会原子性的进行增量操作把当前值加一。下面通过一个例子来认识一下原子操作,请问以下几个选项分别需要几个指令完成?


1)x = 1; ans: 1

2)  y = x; ans: 2. 1st: read x, 2nd: assign to y.

3)  x++; ans: 3 1st: read x, 2nd: add 1 to x, 3rd: assign to x. 


三、Java关于Lock的三种操作tryLock, lock and lockInterrupted的区别。


tryLock是比较潇洒的。如果试过了,lock已经被acquired,则返回false,不再进行尝试。成功acquired则返回true. 


lock是比较执着的,和synchronized()一样,它如果在lock被acquired的时候,会block当前线程,接着并不死心,在将来某个调度它的时候再试一次。


lockInterrupted则是如果当前的lock被acquired则抛出异常,转而去做别的事情。


四、Java的Object.notify/ notifyAll和Object.wait应该怎么用?为什么要和synchronized一起用


为什么这三个方法在Object类?主要原因是JAVA提供的锁是对象级的,每个对象都有一把锁。


notify和notifyAll之间的区别?Object的notify机制是基于非公平机制的,也就是任意选择一个在wait状态的线程进行唤醒。而notifyAll则是唤醒所有的wait线程,看调度选择谁去获得锁(让它们去竞争锁)。


Object.wait() 应该在检查某个条件还没满足的时候使用,无条件wait。原因有以下两个:1)这么做没有任何意义;2)可能导致无人唤醒的局面。导致第二点是因为如果notify或者notifyAll在wait发生前,那么wait就无人唤醒了。反过来看,wait的条件也正是检查notify前需要做的事情是否完成。


为什么要和synchronized一起使用呢?那么应该从生产者-消费者问题来解释好了。因为线程的调度是随意的,我们理想的状态是:


检查队列是否有元素 -- 没有,生产者wait -- 消费者生产元素 -- 通知生产者 -- 生产者醒


但是如果没有synchronized,则有可能:检查队列是否有元素 -- (消费者插入)消费者生产元素 -- 通知生产者 -- (回到生产者)执行没有,生产者wait 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值