• Tags
  •         
  • www.breakyizhan.com
  •    

    我们已经知道,synchronized关键字可以保证线程的安全,但是相对来说,synchronized关键字还是比较重量级的锁。虽然,JDK6之后引入了偏向锁,轻量级锁和重量级锁 ,但是还是比较重量的。而volatile关键字的引入就是为了轻量化。

    Java中volatile的原理

    volatile主要有下面几个特征:

    • Volatile称之为轻量级锁,被volatile修饰的变量,在线程之间是可见的。
    • 可见性:一个线程修改了这个变量的值,在另外一个线程中能够读到这个修改后的值。
    • Synchronized除了线程之间互斥意外,还有一个非常大的作用,就是保证可见性

    但是呢,Synchronized可以实现的,volatile并不一定能实现,对于非原子性的操作,volatile并不一定能实现。

    Java中volatile的使用和实例解析

    我们要保证数据的可见性,就是希望能在set方法之后,才那个这个数字的值,而不是拿到原来的值,下面的程序加上synchronized关键字可以实现(可以试试去掉,synchronized关键字,看看输出的结果):

    
    package com.breakyizhan.thread.t7;
    
    /**
     * 保证可见性的前提
     * 
     * 多个线程拿到的是同一把锁,否则是保证不了的。
     * 
     * @author worker
     *
     */
    public class Demo {
    
    	public int a = 1;
    
    	public synchronized int getA() {
    		return a;
    	}
    
    	public synchronized void setA(int a) {
    		try {
    			Thread.sleep(2);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		this.a = a;
    	}
    
    	public static void main(String[] args) {
    
    		Demo demo = new Demo();
    
    		new Thread(new Runnable() {
    
    			@Override
    			public void run() {
    				demo.setA(10);
    			}
    		}).start();
    
    		new Thread(new Runnable() {
    
    			@Override
    			public void run() {
    				System.out.println(demo.getA());
    			}
    		}).start();
    		
    		try {
    			Thread.sleep(100);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("最终的结果为:" + demo.getA());
    
    	}
    }
    

    输出:

    10
    最终的结果为:10
    

    那么我们知道要保证int a的可见性,还可以在前面加上关键字volatile,具体的代码如下:

    
    package com.breakyizhan.thread.t7;
    
    /**
     * 保证可见性的前提
     * 
     * 多个线程拿到的是同一把锁,否则是保证不了的。
     * 
     * @author worker
     *
     */
    public class Demo {
    
    	public volatile int a = 1;
    
    	public int getA() {
    		return a;
    	}
    
    	public void setA(int a) {
    		try {
    			Thread.sleep(2);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		this.a = a;
    	}
    
    	public static void main(String[] args) {
    
    		Demo demo = new Demo();
    
    		demo.a = 10;
    
    		new Thread(new Runnable() {
    
    			@Override
    			public void run() {
    				System.out.println(demo.a);
    			}
    		}).start();
    		
    		try {
    			Thread.sleep(100);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("最终的结果为:" + demo.getA());
    
    	}
    
    }
    
    

    输出:

    10
    最终的结果为:10
    

    Java中volatile的实用例子

    在第一个程序执行了第10次之后,第二个程序才执行,那么,我们要实现的代码如下:

    
    package com.breakyizhan.thread.t7;
    
    public class Demo2 {
    	
    	public volatile boolean run = false;
    	
    	public static void main(String[] args) {
    		
    		Demo2 d = new Demo2();
    		
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				for(int i = 1;i<=10;i++) {
    					System.err.println("执行了第 " + i + " 次");
    					try {
    						Thread.sleep(1000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    				d.run = true;
    			}
    		}).start();
    		
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				while(!d.run) {
    					// 不执行
    					//自旋
    				}
    				System.err.println("线程2执行了...");
    			}
    		}).start();
    		
    		
    	}
    
    }
    
    

    输出:

    执行了第 1 次
    执行了第 2 次
    执行了第 3 次
    执行了第 4 次
    执行了第 5 次
    执行了第 6 次
    执行了第 7 次
    执行了第 8 次
    执行了第 9 次
    执行了第 10 次
    线程2执行了...
    

    Java中volatile和synchronized的区别

    volatile是为了保证变量的可见性的,是比较轻量级的,而synchronized关键字是比较重量级的。synchronized能实现非原子性操作的线程安全,而volatile实现不了,比如下面这段代码,只能用synchronized来实现:

    public synchronized int getA() {
    		return a++;
    }
    

    还可以看一下Java的并发编程:从synchronized保证线程安全的原理有个getNext的方法,也是非原子性的操作:

    public synchronized int getNext() {
            return value ++;
    }
    

    就是说synchronized能实现所有volatile能实现的功能,而volatile对资源的消耗比较小。

     
    转载请保留页面地址:https://www.breakyizhan.com/java/6638.html