不惜一切代价避免的13种情况
10.4 Synchronized 无法禁止指令重排,却能保证有序性 指令重排是程序运行时 解释器 跟 CPU 自带的加速手段,可能导致语句执行顺序跟预想不一样情况,但是无论如何重排 也必须遵循 as-if-serial。 避免重排的最简单方法就是禁止处理器优化跟指令重排,比如volatile中用内存屏障实现,syn是关键字级别的排他且可重入锁,当某个线程执行到一段被syn修饰的代码之前,会先进行加锁,执行完之后再进行解锁。 当某段代码被syn加锁后跟解锁前,其他线程是无法再次获得锁的,只有这条加锁线程可以重复获得该锁。所以代码在执行的时候是单线程执行的,这就满足了as-if-serial语义,正是因为有了as-if-serial语义保证,单线程的有序性就天然存在了。 10.5 wait 虚假唤醒 虚假唤醒定义: 当一个条件满足时,很多线程都被唤醒了,但只有其中部分是有用的唤醒,其它的唤醒是不对的, 比如说买卖货物,如果商品本来没有货物,所有消费者线程都在wait状态卡顿呢。这时突然生产者进了一件商品,唤醒了所有挂起的消费者。可能导致所有的消费者都继续执行wait下面的代码,出现错误调用。 虚假唤醒原因: 因为 if 只会执行一次,执行完会接着向下执行 if 下面的。而 while 不会,直到条件满足才会向下执行 while下面的。 虚假唤醒 解决办法: 在调用 wait 的时候要用 while 不能用 if。 10.6 notify()底层 1.为何wait跟notify必须要加synchronized锁 synchronized 代码块通过 javap 生成的字节码中包含monitorenter 和 monitorexit 指令线程,执行 monitorenter 指令可以获取对象的 monitor,而wait 方法通过调用 native 方法 wait(0) 实现,该注释说:The current thread must own this object's monitor。 2.notify 执行后立马唤醒线程吗?
notify/notifyAll 调用时并不会真正释放对象锁,只是把等待中的线程唤醒然后放入到对象的锁池中,但是锁池中的所有线程都不会立马运行,只有拥有锁的线程运行完代码块释放锁,别的线程拿到锁才可以运行。 我们看到全局变量global_num前加了关键词__thread修饰,这时,func代码就是又是线程安全的了。为什么呢?其实在上一篇文章中我们讲过,被__thread关键词修饰过的变量放在了线程私有存储中,Thread Local Storage,什么意思呢?意思是说这个变量是线程私有的全局变量:
(编辑:惠州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |