java的volatile关键字

原创
2021/04/15 19:31
阅读数 185
1.解决什么问题
2.实现机制
3.使用场景
  • 解决什么问题?

  1. 内存可见性
    在执行变量写操作后,执行lock指令,这个指令将变量实时写入到主内存而不是处理器的缓存中,然后其他处理器通过缓存一致性协议嗅探到这个变量的变更,将该变量的缓存设置为无效,从而实现内存可见性。
    public class VolatileTest  {
    
    	public static void main(String[] args) throws InterruptedException {
    		Task task = new Task();
    
    		Thread t1 = new Thread(task, "线程t1");
    		Thread t2 = new Thread(new Runnable() {
    			@Override
    			public void run() {
    				try {
    					Thread.sleep(1000);
    					System.out.println("开始通知线程停止");
    					task.stop = true; //修改stop变量值。
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    
    			}
    		}, "线程t2");
    		t1.start();  //开启线程t1
    		t2.start();  //开启线程t2
    		Thread.sleep(1000);
    	}
    }
    
    class Task implements Runnable {
    //    volatile
    	boolean stop = false;
    	int i = 0;
    
    	@Override
    	public void run() {
    		long s = System.currentTimeMillis();
    		while (!stop) {
    			i++;
    		}
    		System.out.println("线程退出" + (System.currentTimeMillis() - s));
    	}
    }
    
  2. 禁止代码重排序 重排序分类:
    • 编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
    • 指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-LevelParallelism,ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
    • 内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
  • 实现机制

    volatile的两条实现原则
    1. Lock前缀指令会引起处理器缓存回写到内存
    2. 一个处理器的缓存回写到内存会导致其他处理器的缓存无效
    
  • volatile不保证原子性

    	package com.pimee.thread.volatiles;
    	public class VolatileDemo2 {
    		public static void main(String[] args) {
    			for (int i = 0; i < 10; i++) {
    				new ThreadTest().start();
    			}
    		}
    	}
    
    	class ThreadTest extends Thread{
    		private static volatile int count;
    
    		@Override
    		public void run() {
    			for (int i = 0; i < 10000; i++) {
    	//            synchronized (ThreadTest.class){
    					count++;
    	//            }
    			}
    			System.out.println(Thread.currentThread().getName() + " count=" + count);
    		}
    	}
    
  • 使用场景

  1. 写入变量值不依赖变量的当前值时。因为如果依赖当前值,将是获取—计算—写入三步操作,这三步操作不是原子性的,而volatile不保证原子性。
  2. 读写变量值时没有加锁。因为加锁本身已经保证了内存可见性,这时候不需要把变量声明为volatile的。
展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部