• 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();
    	}
    }
  • 相关阅读:
    Thread.join()的使用
    Java 编程思想
    LoadRunner 常见错误
    Selenium+IDEA+Maven+TestNG环境搭建
    计算机基本知识了解(二)
    Java中int和Integer的区别
    计算机基本知识了解(一)
    Jmeter安装及环境配置
    app稳定性测试-monkey测试
    .net framework
  • 原文地址:https://www.cnblogs.com/new0801/p/6146610.html
Copyright © 2020-2023  润新知