【多线程不安全的原因与解决办法】

2017-02-08  本文已影响0人  hello高world

1、 线程不安全的特征

通过上面一个博文,我们可以注意到不安全例子的特点:

  • 有实例变量或静态变量

如果有碰到上面这样的,请要注意了!!!

2、不安全的原因

2.1 原子性

  • count++ 不是原子操作

2.1 有序性

有序性问题(指令重排或者工作内存和主存同步延迟)
见上一篇博客中的——神奇的while例子, 底层可能优化成这样:

while(!done)
   i++;

转成这样了:

if(!done) {
   while(true)
   i++;
}

指令被重排了,工作线程done无法同步到主存中。

2.3 可见性

比如上面的例子,主线程更改了done,但子线程看不到done的变化。

3 保存并发三个特性的手段

  • 原子性:AtomicXX、synchronized、使用Map的原子操作。等等

4 为什么?

  • 为什么AtomicXX有原子性功效?

请看规定的:
1、Java内存模型中的八条可保证happen—before的规则
2、Java内存模型中的八条交互规则
3、volatile特殊规则

套用上面规则来分析synchronized,其他类似。

  • 可见性:【规定的某条规则】对一个变量执行unlock之前,必须先把此变量同步回主内存中。

5、 synchronized是什么鬼?

javap后的synchronized方法.png 具体方法

synchronized修饰的代码库底层指令集有两个: monitorenter/monitorexit

<b>1、 monitor是什么鬼?</b>
<b>2、 为什么会有两个monitorexit</b>
-> 第二个monitorexit是怕你出了异常,做了释放锁的动作。

6、 什么是monitor?

7、为什么要引入管程?

解决类似以下两个问题 from《现代操作系统》:

即: <b>两个或多个线程读写某些共享数据,而最后取决于线程运行的精确时序。——竞争条件</b>

如何避免竞争条件?
——互斥。线程A对共享资源使用完之前线程B无法使用。

互斥的手段:
信号量、互斥量、管程、CPU中断等

8、信号量解决互斥

8.1 什么是信号量

自行补脑: http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html

8.2 解决互斥栗子(来自《现代操作系统》)

生产者和消费者问题.png

注意:信号量大于=0,如果=0,再去获取信号量的话,就会阻塞住。

问题:交换下生产者中的两行,如下:

Paste_Image.png
管程织入

还有一个问题就是进入临界区(共享数据的读写代码段称为临界区)之后,如果里面因为一个条件需要阻塞,那这个锁就无法释放对吧。
所以管程模型,提出了类似于java中的wait/notify/notifyAll(条件队列)用于解决这个问题。当条件阻塞,调用wait让出这个锁。当条件满足notify,让另一个线程重新获得这个锁。

<b>所以wait/notify/notifyAll(条件队列)一定要在synchronized中使用,否则会报错</b>

上一篇 下一篇

猜你喜欢

热点阅读