volatile实现可见性但不保证原子性

volatile实现可见性但不保证原子性

        volatile关键字:

  • 能够保证volatile变量的可见性
  • 不能保证volatile变量复合操作的原子性

         volatile如何实现内存可见性:

         深入来说:通过加入内存屏障和禁止重排序优化来实现的。

  • 对volatile变量执行写操作时,会在写操作后加入一条store屏障指令
  • 对volatile变量执行读操作时,会在读操作前加入一条load屏障指令

         通俗地讲:volatile变量在每次被线程访问时,都强迫从主内存中重读该变量的值,而当该变量发生变化时,又会强迫线程将最新的值刷新到主内存。这样任何时刻,不同的线程总能看到该变量的最新值。

         线程写volatile变量的过程:

  • 改变线程工作内存中volatile变量副本的值
  • 将改变后的副本的值从工作内存刷新到主内存

         线程读volatile变量的过程:

  • 从主内存中读取volatile变量的最新值到线程的工作内存中
  • 从工作内存中读取volatile变量的副本

         volatile不能保证volatile变量复合操作的原子性:

private int number = 0;
number++; //不是原子操作

         它分为三步:
         读取number的值
         将number的值加1
         写入最新的number的值

          保证number自增操作的原子性:

  • 使用synchronized关键字
  • 使用ReentrantLock
  • 使用AtomicInteger

          使用synchronized关键字

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author InJavaWeTrust
 */
public class TestSyn implements Runnable {

	private int number = 0;

	public int getNumber() {
		return this.number;
	}

	public void run() {
		increase();
	}

	public void increase() {
		synchronized (this) {
			this.number++;
		}
	}

	public static void main(String[] args) {
		ExecutorService exec = Executors.newFixedThreadPool(1000);
		TestSyn syn = new TestSyn();
		for (int i = 0; i < 1000; i++) {
			exec.submit(syn);
		}
		System.out.println("number : " + syn.getNumber());
		exec.shutdown();
	}
}

          使用ReentrantLock

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * @author InJavaWeTrust
 */
public class TestRee implements Runnable {

	private Lock lock = new ReentrantLock();
	private int number = 0;

	public int getNumber() {
		return this.number;
	}

	public void run() {
		increase();
	}

	public void increase() {
		lock.lock();
		try {
			this.number++;
		} finally {
			lock.unlock();
		}
	}

	public static void main(String[] args) {
		TestRee ree = new TestRee();
		ExecutorService exec = Executors.newFixedThreadPool(1000);
		for (int i = 0; i < 1000; i++) {
			exec.submit(ree);
		}
		System.out.println("number : " + ree.getNumber());
		exec.shutdown();
	}
}

          使用AtomicInteger

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author InJavaWeTrust
 */
public class TestAtomic implements Runnable {

	private static AtomicInteger number = new AtomicInteger(0);

	public void run() {
		increase();
	}

	public void increase() {
		number.getAndAdd(1);
	}

	public static void main(String[] args) {
		TestAtomic ato = new TestAtomic();
		ExecutorService exec = Executors.newFixedThreadPool(1000);
		for (int i = 0; i < 1000; i++) {
			exec.submit(ato);
		}
		System.out.println("number : " + number.get());
		exec.shutdown();
	}
}
原文地址:https://www.cnblogs.com/new0801/p/6146610.html