美文网首页
【多线程不安全的原因与解决办法】

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

作者: hello高world | 来源:发表于2017-02-08 20:25 被阅读0次

1、 线程不安全的特征

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

  • 有实例变量或静态变量
  • 类似于count++(读-操作-写)
  • 有if-then
  • 有发布set方法
  • 多个线程对同一个对象操作

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

2、不安全的原因

2.1 原子性

  • count++ 不是原子操作
  • ConcurrentHashMapTest中的if-then也不是原子操作

2.1 有序性

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

while(!done)
   i++;

转成这样了:

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

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

2.3 可见性

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

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

  • 原子性:AtomicXX、synchronized、使用Map的原子操作。等等
  • 有序性: synchronized、volatile
  • 可见性: synchronized、volatile、final
    !!!万能的synchronized。

4 为什么?

  • 为什么AtomicXX有原子性功效?
  • 为什么synchronized有原子性、可见性、有序性功效?
  • 为什么volatile有可见性、有序性功效?

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

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

  • 可见性:【规定的某条规则】对一个变量执行unlock之前,必须先把此变量同步回主内存中。
  • 有序性和原子性:【规定的某条规则】一个变量在同一个时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁

5、 synchronized是什么鬼?

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

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

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

6、 什么是monitor?

7、为什么要引入管程?

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

  • 火车订票系统,只有最后一张票,但有2个客户试图争夺这张火车票。
  • 线程A负责读取mysql数据,线程B负责打印数据。线程B需要等待A的完成,否则打印就是不正确的。

即: <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
  • <b>请分析当empty=0和full=10情况,是不是会发生死锁?嘿嘿。。
    所以管程的优势是,有编译器来处理进入临界区代码和出临界区代码。我们只要加了synchronized,由编译器自动帮我们编织了monitorenter和monitorexit。
    </b>
管程织入

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

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

相关文章

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

    1、 线程不安全的特征 通过上面一个博文,我们可以注意到不安全例子的特点: 有实例变量或静态变量 类似于count...

  • hashmap多线程不安全的原因

    我们知道hashmap在多线程下是不安全的,那么为什么不安全,这个原因是什么呢。其实核心原因在于扩容的时候多线程的...

  • iOS多线程到底不安全在哪里?

    iOS多线程到底不安全在哪里? iOS多线程到底不安全在哪里?

  • 几个小问题

    1、FMDB与多线程 SQLITE默认的线程模式是串行模式, 是线程安全的FMDatabase多线程不安全, 单个...

  • HashMap 与 ConcurrentHashMap

    HashMap 与 ConcurrentHashMap 一、背景: 线程不安全的HashMap:因为多线程环境下,...

  • Andriod not permitted by network

    导致上面问题的原因是:Andriod 9 系统更新,组织Http 不安全请求,解决办法:解决方法: 如果你的应用加...

  • HashMap为什么线程不安全

    hash碰撞与扩容导致 一直以来都知道HashMap是线程不安全的,但是到底为什么线程不安全,在多线程操作情况下什...

  • ArrayList与LinkedList

    ArrayList与LinkedList都是线程不安全的,都没有锁的机制 线程安全解决办法 : 方法1: Coll...

  • 关于HashMap 、HashTable and Concur

    线程不安全的HashMap 多线程环境下使用HashMap会引起死循环,原因就在于HashMap底层数据结构是有一...

  • Java基础篇-HashMap多线程问题

    常会说到HashMap在多线程下是不安全的,那么不安全会引起什么问题呢? 多线程下,对一个HashMap进行修改时...

网友评论

      本文标题:【多线程不安全的原因与解决办法】

      本文链接:https://www.haomeiwen.com/subject/omsbittx.html