volatile是java中提供的一种轻量级的同步机制,相比于synchronized更加轻量,因为volatile避免了线程频繁的上下文切换和调度,但是也有缺点,同步性差并且使用起来易出错。
public class VolatileTest1 {
private static volatile int num = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
num++;
}
});
thread.start();
}
System.out.println("num=" + num);
}
}
结果
num=5657
num=4414
num=7491
…(完全随机)
public class VolatileTest1 {
public static volatile int num = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10000; j++) {
synchronized (VolatileTest1.class) {
num++;
}
}
}
}).start();
}
// 保证线程执行完毕
while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println("num=" + num);
}
}
结果:
num=100000
(2)使用lock锁住该方法
public class VolatileTest3 {
public static volatile int num = 0;
public static Lock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10000; j++) {
lock.lock();
try {
num++;
}finally {
lock.unlock();
}
}
}
}).start();
}
// 保证线程执行完毕
while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println("num=" + num);
}
}
结果:
num=100000
(3)使用并发原子操作类AtomicInteger ,其原理是通过CAS循环的方式来保证原子性
public class VolatileTest5 {
public static volatile AtomicInteger num = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10000; j++) {
num.getAndIncrement();
}
}
}).start();
}
// 保证线程执行完毕
while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println("num=" + num);
}
}
结果:
num=100000
public class InstanceTest{
private volatile static InstanceTest instance;
public static InstanceTest getInstance(){ //1
if(instance == null){ //2
synchronized(InstanceTest.class){ //3
if(instance == null){ //4
instance = new InstanceTest(); //5
}
}
}
return instance; //6
}
}
在并发情况下,如果没有volatile修饰的话,代码中5处会出现问题instance = new InstanceTest();
这个可以分为三步,
a. memory = allocate() //分配内存
b. ctorInstanc(memory) //初始化对象
c. instance = memory //设置instance指向刚分配的地址
在编译时,指令重排序,不一定按照a->b->c的顺序来执行,可能会是a->c->b,多线程下一个线程在执行完a,马上执行c,设置instance指向刚分配的地址,这个时候另外一个线程刚好到第2步判断,则会出现不为空,直接跳到第6步,而此时并没有初始化,会返回一个未初始化的对象。
volatile可以保证线程的可见性并提供一定的有序性,底层采用的是“内存屏障”来实现的,但是不能保证原子性,需要结合lock,synchornized,AtomicInteger 等来实现线程并发安全。
内存屏障会提供三个功能:
借鉴学习-侵删