JAVA中Volatile关键字,在编写多线程和高并发的程序的时候,尤为重要.

其中Volatile涉及到CPU中的Cache Line 和内存屏障, 这里就不去深究了.

详细资料可以去看MESI协议.

真实项目中, 最近在优化和重构时候, 发现了一些代码问题, 重构代码之后, 把知识点以后整理了出来.

下面例子里, 是一段生产环境代码扣出来的逻辑, 功能上看上去并没有太大的问题. 单元测试也测不出来.

但是细致观察, 判断有无加锁这段代码, 却出了问题. 每次判断, 都会同步! 因为方法有synchronized关键字.

当然这里 synchronized去掉就可以了, 没有锁竞争, 自然速度就快了. (一定要记得在同步块中,再判断一次有无初始化, 不然初始化可能会懵逼的执行多次, 仍然可能有多个线程进入到同步块中.)

synchronized 时候,执行时间12000ms, 去掉以后..180ms..

package simple;import java.util.HashMap;import java.util.Map;import java.util.concurrent.CountDownLatch;public class SynTest {    private static int THREAD_COUNT = 200;    private static int CALL = 1000000;    public static void main(String[] args) throws Exception {        CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT);        WorkThread[] threads = new WorkThread[THREAD_COUNT];        for (int i = 0; i < THREAD_COUNT; i++) {            threads[i] = new WorkThread(CALL, countDownLatch);        }        long startTime = System.currentTimeMillis();        for (int i = 0; i < THREAD_COUNT; i++) {            threads[i].start();        }        countDownLatch.await();        long endTime = System.currentTimeMillis();        System.out.println(endTime - startTime);    }    private static Map
 map = null;    public static String getProperty(String key) {        if (!isInit()) {            init();        }        return map.get(key);    }    public synchronized static boolean isInit() {        return map != null;    }    public synchronized static void init() {        if (map != null) {            return;        }        map = new HashMap
();        map.put("TEST", "TEST");    }    static class WorkThread extends Thread {        private int times;        private CountDownLatch countDownLatch;        public WorkThread(int times, CountDownLatch latch) {            this.times = times;            this.countDownLatch = latch;        }        public void run() {            for (int i = 0; i < times; i++) {                SynTest.getProperty("TEST");            }            countDownLatch.countDown();        }    }}

如果我们判断是拿volatile做比较呢? (此处仅仅是测试了下volatile的性能损耗,不加会更快)

实际为250ms, 损耗非常小. 比起没有锁, 仅仅多了70ms左右.

synchronized, 一般性的并发, 用用就可以了. 高度的并发, 还是用基于volatile的一系列方法. 比如反射出Unsafe, 或者AtomicXXX的.

package simple;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
public class VolatileTest {
    private static int THREAD_COUNT = 200;
    private static int CALL = 1000000;
    public static void main(String[] args) throws Exception {
        CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT);
        WorkThread[] threads = new WorkThread[THREAD_COUNT];
        for (int i = 0; i < THREAD_COUNT; i++) {
            threads[i] = new WorkThread(CALL, countDownLatch);
        }
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < THREAD_COUNT; i++) {
            threads[i].start();
        }
        countDownLatch.await();
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    }
    private static volatile boolean init = false;
    private static Map<String, String> map = null;
    public static String getProperty(String key) {
        if (!isInit()) {
            init();
        }
        return map.get(key);
    }
    public static boolean isInit() {
        return init;
    }
    public synchronized static void init() {
        if (init) {
            return;
        }
        map = new HashMap<String, String>();
        map.put("TEST", "TEST");
        init = true;
    }
    static class WorkThread extends Thread {
        private int times;
        private CountDownLatch countDownLatch;
        public WorkThread(int times, CountDownLatch latch) {
            this.times = times;
            this.countDownLatch = latch;
        }
        public void run() {
            for (int i = 0; i < times; i++) {
                VolatileTest.getProperty("TEST");
            }
            countDownLatch.countDown();
        }
    }
}