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

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>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,372评论 11 349
  • 参考链接:http://smallbug-vip.iteye.com/blog/2275743 在多线程开发的过程...
    时之令阅读 1,575评论 2 5
  • Java-Review-Note——4.多线程 标签: JavaStudy PS:本来是分开三篇的,后来想想还是整...
    coder_pig阅读 1,682评论 2 17
  • 一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这么写 publicclassUnsa...
    Martin说阅读 2,269评论 0 6
  • “不要离开这里!”母亲说着便离开了小路,走进了一人多高的玉米地里。 此刻只剩他一个人站在这条穿过玉米地的小路上。对...
    arty3阅读 19,195评论 0 0