zoukankan      html  css  js  c++  java
  • 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();
    	}
    }
  • 相关阅读:
    #检查磁盘使用率超过90%,并且后台进程没有rman在跑,就运行 /data/script/del_dg_arch.sh 脚本清理归档
    linux shell数据重定向
    创建用户
    Linux HA+ Oracle 安装维护手册
    解决UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range
    Linux 文件不能被root修改与编辑原因
    python中的时间戳和格式化之间的转换
    Python-Redis-发布订阅
    Python-Redis-常用操作&管道
    Python-Redis-Set
  • 原文地址:https://www.cnblogs.com/muyuge/p/6152006.html
Copyright © 2011-2022 走看看