第一篇:Java并发编程的三大特性:原子性、可见性、有序性

并发是什么呢?

并发指的是Java中有多线程并发运行。

为什么会有并发?

因为一个线程在执行的过程中不仅会用到cpu资源,还会用到IO,也就是输入输出。IO的速度远远比不上CPU的运算速度。如果线程在IO的时候,不放弃CPU资源,就会导致CPU空闲,以至于CPU的利用率十分低下。所以就引入了多线程,当一个线程要请求IO的时候,会放弃cpu资源。这个时候,其他线程可以使用cpu。这就提高了cpu的利用率。

虽然线程之间的切换有额外的资源消耗,但是带来的回报更大。所以多线程是主流。

Java并发编程有三大特性:

1、可见性
因为线程所需的数据都存在了内存中,当cpu需要数据的时候,如果每次都去内存中去读取的话,是不合适的。因为CPU的运算是十分快的,是到内存中读取数据的速度的指数级倍数,二者是不匹配。所以这就会出现CPU利用率不高的问题。所以CPU内增加了一个高速缓存,高速缓存读取数据的效率是很高的,是可以与CPU匹配的,所以线程会将内存中的数据拷贝到CPU高速缓存中,读取和改写的是CPU高速缓存中的数据,然后再运算结束后,再将数据写入到内存中。

我们都知道现在的CPU都是多核的,所以说一个线程对应了一个高速缓存,如果多个线程同时读取一个变量的时候,会在每个高速缓存中都拷贝一份数据,彼此之间是不可见的。

不可见的话,出导致并发的一些问题,接下来我们举个例子

假如有A、B两个线程,
1、A首先执行依次X++操作,因为此时CPU缓存1中不存在X值,所以会从内存中将x=1调入,然后进行X++操作,然后将X=2写入到CPU缓存1和内存中。
2、B接着执行X++操作,因为CPU缓存2中不存在X值,所以将X=2调入CPU缓存2中,进行X++操作,然后将X=3写入到CPU缓存2和内存中。
3、这时A再次执行X++操作,因为此时cpu缓存1中已经存在X=2了,所以直接使用,执行X++,将X=3将写入到CPU缓存1和内存中。

正确结果应该是4,现在却变成了3,都是因为内存不可见的问题。
在这里插入图片描述

对于可见性问题,Java提供了volatile关键字来修饰变量。当变量被volatile修饰后,CPU读取的时候,将会禁用缓存,每次都去内存中读取内存。

2、原子性
原子操作是Java中的最小操作过程。原子的意思就是操作不可以被中断。
还拿之前的例子来说明。

x++其实并不是一个原子性操作,它被分为三部分:
1、读取x的值
2、x+1
3、将x+1写入到内存中

当按照以下步骤处理时,会出现线程不安全
1、当A读取先完成了1、2步骤后,然后被中断
2、B开始执行,执行力1、2、3步骤,x变为了2
3、A执行3步骤,x变为2

还是出现了内存丢失。

对于原子性,Java中引入了锁来解决,当A进行X++操作时,对加锁,在代码执行完成后,才会释放锁。在A持有锁的期间,如果B想要执行X++操作,则会被阻塞。

加锁的时候,其他线程会被切换,当再次被运行的时候线程会重新从内存中读取值,所以枷锁本身已经保证了可见性。

随着计算机硬件的发展,Java又引入原子类来解决这一问题。这个具体的实现我们以后单独说。

3、有序性

由于编译会对代码进行优化,所以有的时候会调整代码的执行顺序。有的时候也会导致意想不到的bug。

public void test1(){//线程A执行
	obj = new Object();
	init = true;
}

public void test2(){//线程B执行
   if(init){
       obj.toString();
   }
}

比如上述代码,从test1方法看来,obj = new Object()和init = true 看起来时没啥关系的,有可能编译的时候,会将init = true编译到前面。

假如当A执行完init = true后,线程A停止,然后切换到了线程B,这个时候init = true,会进入 obj.toString()。但是此时obj 还未初始化,会报异常!

将变量用volatile修饰的时候,会避免指令重排。
当变量被volatile修饰时,
1、如果是写volatile,那么写volatile之前的语句不会被安排到写volatile之后
2、如果是读volatile,那么读volatile之后的语句不会被安排到读volatile之前。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值