同线程数量,同循环数量,比较运行时间。废话不多说,直接上代码。
public class Compare_Syn_CAS {
public static final int THREAD_SIZE = 100;
public static final long TIMES = (long)1e7;
public static final Object lock = new Object();
public static AtomicLong cnt1 = new AtomicLong(0);
public static long cnt2 = 0L;
public static void CountCAS() throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
CountDownLatch countDownLatch = new CountDownLatch(THREAD_SIZE);
long start = System.currentTimeMillis();
for (int i = 0; i < THREAD_SIZE; i ++) {
executorService.submit(() -> {
for (long j = 0; j < TIMES; j ++) cnt1.getAndIncrement();
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
public static void CountSyn() throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
CountDownLatch countDownLatch = new CountDownLatch(THREAD_SIZE);
long start = System.currentTimeMillis();
for (int i = 0; i < THREAD_SIZE; i ++) {
executorService.submit(() -> {
for (long j = 0L; j < TIMES; j ++) {
synchronized (lock) {
cnt2++;
}
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
public static void main(String[] args) throws InterruptedException {
CountCAS();
System.out.println("============");
CountSyn();
}
}
运行时间对比:
24617, 52121
电脑配置:4核8线程 CPU
synchonized 同步属于一种悲观的并发策略。无论共享数据是否真的会出现竞争,它都要进行加锁(这里讨论的是概念模型,实际上虚拟机会优化掉很大一部分不必要的加锁)、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作。CAS 会快很多。
但是注意,如果上面代码,我们把 synchronized 放到 for 循环外,那么 synchronized 会快得多,因为这时 synchronized 全是偏向锁的形态,这会比 CAS 快得多。