Java并发编程中如何保证原子性

原子性,可见性,有序性是并发的三大特征,所谓原子性,就是一个操作要么全部执行,要么都不执行。

如下所示,在一个类中,定义一个静态变量int var=0,现在开启20个线程,每个线程都执行相同的操作,即对var实行10000次++操作,线程退出,然后打印var的值。

package com.xxx.cas;

public class PlusPlusOP {
	public static int var = 0;
	
	public static void plusAndPlus(){
		var++;
	}
	
	public static void main(String[] args) {
		Thread threads[] = new Thread[20];
		for(int i=0;i<20;i++){
			threads[i] = new Thread(new Runnable() {
				
				@Override
				public void run() {
					for(int i=0;i<10000;i++){	
						plusAndPlus();
					}
				}
			});
			threads[i].start();
		}
		
		while(Thread.activeCount()>1){
			Thread.yield();
		}
		System.out.println("var=>"+var);
	}
}

默认,没有对原子操作做特殊的处理,我们的到的结果各种各样,但就不是200000。如下所示:

 

这是一个很常见的并发问题,涉及到的是原子操作,var++这个动作,其实分为了三个过程:

  1. 读取var的值
  2. ++操作
  3. 写入var的值 

多线程并发的情况下,有可能第一个线程获取了var=10000,即将执行++操作,这时候另一个线程也来获取var,这时候获取的应该也是10000,当他们都执行完成的时候,本来应该是10002,但是实际上,因为并发的原因,导致了最终的结果是10001。所以我们看到的结果是一个小于200000的数字,程序在这种情况下运行,得到这个结果是正常的。再次运行,可能还是一个小于200000的结果。

那么如何解决这个原子性的问题呢,其实就是要保证var++这个动作不能被拆开,一旦进入读取var的值,那么接下来只有执行了写入var的值之后,别的线程才可以运行读取var的值操作。这就需要var++这个操作是同步的,解决办法可以有如下三种:

  • synchronized同步代码块
  • cas原子类工具
  • lock锁机制

三种解决方案的具体实现:

synchronized同步代码块

cas原子类工具

lock锁

 

猜你喜欢

转载自blog.csdn.net/feinifi/article/details/94174492