我们已经知道,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++;
}
public synchronized int getNext() {
return value ++;
}
就是说synchronized能实现所有volatile能实现的功能,而volatile对资源的消耗比较小。