码迷,mamicode.com
首页 > 其他好文 > 详细

【总结】并发编程

时间:2020-06-14 15:11:37      阅读:56      评论:0      收藏:0      [点我收藏+]

标签:依赖   发送消息   安全性   子线程   增强   ade   table   通信   join()   

一.java内存模型

1.线程通信机制

1.共享内存(java使用)

共享内存这种方式比较常见,我们经常会设置一个共享变量。然后多个线程去操作同一个共享变量。从而达到线程通讯的目的。例如,我们使用多个线程去执行页面抓取任务,我们可以使用一个共享变量count来记录任务完成的数量。每当一个线程完成抓取任务,会在原来的count上执行加1操作。这样每个线程都可以通过获取这个count变量来获得当前任务的完成情况。当然必须要考虑的是共享变量的同步问题,这也共享内存容易出错的原因所在。
技术图片

2.消息传递

消息传递方式采取的是线程之间的直接通信,不同的线程之间通过显式的发送消息来达到交互目的。消息传递最有名的方式应该是actor模型了(erlang使用此模型)。在这种模型下,一切都是actor(类似于面向对象的oo),所有的actor之间的通信都必须通过传递消息才能达到。每个actor都有一个收件箱(消息队列,所以它是一个异步模型)用来保存收到其他actor传递来的消息
技术图片

2.内存模型

1.重排序

编译器和处理器可能会对操作做重排序。编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序
怎样判断两个操作存在依赖关系?
如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性

名称 代码示例 说明
写后读 a = 1;b = a; 写一个变量之后,再读这个位置
写后写 a = 1;a = 2; 写一个变量之后,再写这个变量
读后写 a = b;b = 1; 读一个变量之后,再写这个变量

上面三种情况,只要重排序两个操作的执行顺序,程序的执行结果将会被改变。

2.as-if-serial

as-if-serial 语义的意思指:不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。编译器,和处理器都必须遵守 as-if-serial 语义

3.happens-before

在并发环境下,指令重排序可能出现问题,为了避免编译优化对并发编程安全性的影响,需要happens-before规则定义一些禁止编译优化的场景,保证并发编程的正确性

public class VolatileExample {
    int x = 0 ;
    volatile boolean v = false;
    public void writer(){
        x = 42;
        v = true;
    }

    public void reader(){
        if (v == true){
            // 这里x会是多少呢
        }
    }
}

jdk1.5之前,线程B读到的变量x的值可能是0,也可能是42,jdk1.5之后,变量x的值就是42了。原因是jdk1.5中,对volatile的语义进行了增强.来看一下happens-before规则在这段代码中的体现。

1.规则1:程序顺序性规则
一个线程中,按照程序的顺序,前面的操作happens-before后续的任何操作(对于这一点,可能会有疑问。顺序性是指,我们可以按照顺序推演程序的执行结果,但是编译器未必一定会按照这个顺序编译,但是编译器保证结果一定==顺序推演的结果)
2.规则二:volatile规则
对一个volatile变量的写操作,happens-before后续对这个变量的读操作
3.规则三:传递性规则
如果A happens-before B,B happens-before C,那么A happens-before C
jdk1.5的增强就体现在这里。回到上面例子中,线程A中,根据规则一,对变量x的写操作是happens-before对变量v的写操作的,根据规则二,对变量v的写操作是happens-before对变量v的读操作的,最后根据规则三,也就是说,线程A对变量x的写操作,一定happens-before线程B对v的读操作,那么线程B在注释处读到的变量x的值,一定是42
4.规则四:管程中的锁规则
对一个锁的解锁操作,happens-before后续对这个锁的加锁操作
5.规则五:线程start()规则
主线程A启动线程B,线程B中可以看到主线程启动B之前的操作。也就是start() happens before 线程B中的操作
6.规则六:线程join()规则
主线程A等待子线程B完成,当子线程B执行完毕后,主线程A可以看到线程B的所有操作。也就是说,子线程B中的任意操作,happens-before join()的返回

【总结】并发编程

标签:依赖   发送消息   安全性   子线程   增强   ade   table   通信   join()   

原文地址:https://www.cnblogs.com/muacheng/p/13124687.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!