Java的并发编程:深入理解volatile的原理和使用

作者: Arvin Chen 分类: Java 来源: Break易站(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对资源的消耗比较小。

  •   本文标题:Java的并发编程:深入理解volatile的原理和使用 - Break易站
    转载请保留页面地址:https://www.breakyizhan.com/java/6638.html
    扫描二维码添加微信 
  • ,领取淘宝优惠券,淘宝购物更优惠。现在添加微信,还可以领取机械键盘优惠券!添加微信后,分享淘宝选中的机械键盘给淘宝机器人即可领取!
    支持我们,就用微信淘宝!

    发表笔记

    电子邮件地址不会被公开。 必填项已用*标注

    更多阅读