第21章 – 并发 – 同步机制性能测试(Lock,synchronized,Atomic类)(P749)
第21章 – 并发 – 同步机制性能测试(Lock,synchronized,Atomic类)(P749)
1. 由执行结果可知:
Lock,synchronized,Atomic中,synchronized的性能最差,Atomic性能最好.
但是Atomic类只有在非常简单的情况下才有用,这些情况包括,你只有一个要被修改的Atomic对象,
并且这个对象独立于其他所有的对象.
Lock 性能优于synchronized,但是Lock使得程序可读性降低.
执行结果:
Warmup
BaseLine : 36931789
============================
Cycles : 50000
BaseLine : 11323226
synchronized : 76147108
Lock : 39562849
Atomic : 13717666
synchronized/BaseLine : 6.72
Lock/BaseLine : 3.49
Atomic/BaseLine : 1.21
synchronized/Lock : 1.92
synchronized/Atomic : 5.55
Lock/Atomic : 2.88
============================
Cycles : 100000
BaseLine : 18092244
synchronized : 226067000
Lock : 49212400
Atomic : 32785731
synchronized/BaseLine : 12.50
Lock/BaseLine : 2.72
Atomic/BaseLine : 1.81
synchronized/Lock : 4.59
synchronized/Atomic : 6.90
Lock/Atomic : 1.50
============================
Cycles : 200000
BaseLine : 86070716
synchronized : 442244196
Lock : 98803060
Atomic : 77051972
synchronized/BaseLine : 5.14
Lock/BaseLine : 1.15
Atomic/BaseLine : 0.90
synchronized/Lock : 4.48
synchronized/Atomic : 5.74
Lock/Atomic : 1.28
============================
Cycles : 400000
BaseLine : 85726538
synchronized : 754004489
Lock : 186101585
Atomic : 98848876
synchronized/BaseLine : 8.80
Lock/BaseLine : 2.17
Atomic/BaseLine : 1.15
synchronized/Lock : 4.05
synchronized/Atomic : 7.63
Lock/Atomic : 1.88
============================
Cycles : 800000
BaseLine : 168371399
synchronized : 1563667450
Lock : 393607288
Atomic : 229484753
synchronized/BaseLine : 9.29
Lock/BaseLine : 2.34
Atomic/BaseLine : 1.36
synchronized/Lock : 3.97
synchronized/Atomic : 6.81
Lock/Atomic : 1.72
代码:
package concurrency; import java.util.Random; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; abstract class Accumulator { public static long cycles = 50000L; private static final int N = 4; //同时启动的Modifier和Reader的个数N=4 表示同时启动4个Modifier和4个Reader //每个Modifier和Reader 在run中循环cycles次执行accumulate()和read() public static ExecutorService exec = Executors.newFixedThreadPool(N * 2); private static CyclicBarrier barrier = new CyclicBarrier(N * 2 + 1); protected volatile int index = 0; protected volatile long value = 0; protected long duration = 0; protected String id = "error"; protected final static int SIZE = 100000; protected static int[] preLoaded = new int[SIZE]; static { // Load the array of random numbers: Random rand = new Random(47); for (int i = 0; i < SIZE; i++) preLoaded[i] = rand.nextInt(); } public abstract void accumulate(); public abstract long read(); //在上面这两个方法中 分别使用不同的同步机制,保证同一时刻,只有一个线程可以调用这两个方法当中的一个 //BaseLine extends Accumulator 中这两个方法的实现没有使用任何同步机制 //导致两个方法不是线程安全的,但是是性能最好的,从而作为一个基准 // private class Modifier implements Runnable { public void run() { for (long i = 0; i < cycles; i++) accumulate(); try { barrier.await(); } catch (Exception e) { throw new RuntimeException(e); } } } private class Reader implements Runnable { private volatile long value; public void run() { for (long i = 0; i < cycles; i++) value = read(); try { barrier.await(); } catch (Exception e) { throw new RuntimeException(e); } } } public void timedTest() { long start = System.nanoTime(); for (int i = 0; i < N; i++) { exec.execute(new Modifier()); exec.execute(new Reader()); //N个Modifier() 和 N个Reader() 分别调用了1次的run进行一次循环的accumulate() 和 read()(5000L次) //然后调用barrier.await(); 挂起 //accumulate() 和 read() 这两个抽象方法放到子类中实现, //有的子类不同步,有的使用synchronized同步,有的使用Lock同步,有的使用Atomic对象 //这样即可测试使用不同同步方法的性能(有耗时时间表示) } try { barrier.await(); //确保每个Modifier和Reader 中的run方法也必须执行完毕 //同时 假如Modifier和Reader中有先执行到barrier.await();挂起的线程继续执行,然后从run()方法中返回 } catch (Exception e) { throw new RuntimeException(e); } duration = System.nanoTime() - start; System.out.printf("%-13s: %13d\n", id, duration); } public static void report(Accumulator acc1, Accumulator acc2) { System.out.printf("%-22s: %.2f\n", acc1.id + "/" + acc2.id, (double) acc1.duration / (double) acc2.duration); } } class BaseLine extends Accumulator { { id = "BaseLine"; } public void accumulate() { value += preLoaded[index++]; if (index >= SIZE) index = 0; } public long read() { return value; } } class SynchronizedTest extends Accumulator { { id = "synchronized"; } public synchronized void accumulate() { value += preLoaded[index++]; if (index >= SIZE) index = 0; } public synchronized long read() { return value; } } class LockTest extends Accumulator { { id = "Lock"; } private Lock lock = new ReentrantLock(); public void accumulate() { lock.lock(); try { value += preLoaded[index++]; if (index >= SIZE) index = 0; } finally { lock.unlock(); } } public long read() { lock.lock(); try { return value; } finally { lock.unlock(); } } } class AtomicTest extends Accumulator { { id = "Atomic"; } private AtomicInteger index = new AtomicInteger(0); private AtomicLong value = new AtomicLong(0); public void accumulate() { // Oops! Relying on more than one Atomic at // a time doesn't work. But it still gives us // a performance indicator: //不同步的代码 是这样的value += preLoaded[index++]; //这里同时依赖value和index两个Atomic对象 //这样使用Atomic对象也不能保证程序正常执行了 int i = index.getAndIncrement(); value.getAndAdd(preLoaded[i]); if (++i >= SIZE) index.set(0); } public long read() { return value.get(); } } public class SynchronizationComparisons { static BaseLine baseLine = new BaseLine(); static SynchronizedTest synch = new SynchronizedTest(); static LockTest lock = new LockTest(); static AtomicTest atomic = new AtomicTest(); static void test() { System.out.println("============================"); System.out.printf("%-12s : %13d\n", "Cycles", Accumulator.cycles); baseLine.timedTest(); synch.timedTest(); lock.timedTest(); atomic.timedTest(); Accumulator.report(synch, baseLine); Accumulator.report(lock, baseLine); Accumulator.report(atomic, baseLine); Accumulator.report(synch, lock); Accumulator.report(synch, atomic); Accumulator.report(lock, atomic); } public static void main(String[] args) { int iterations = 5; // Default if (args.length > 0) // Optionally change iterations iterations = new Integer(args[0]); // The first time fills the thread pool: System.out.println("Warmup"); baseLine.timedTest(); //这个用于初始化类中的线程池,使用Executors.newFixedThreadPool(N * 2);创建线程池和线程,这里就把线程池和线程创建好了. //这样后面的测试时间不收创建线程的时间影响. //同时也将preLoaded[]数组填满 // Now the initial test doesn't include the cost // of starting the threads for the first time. // Produce multiple data points: for (int i = 0; i < iterations; i++) { test(); Accumulator.cycles *= 2; } //for中循环测试5次 Accumulator.exec.shutdown(); } }
赞 赏
微信赞赏
支付宝赞赏
本文固定链接: https://www.jack-yin.com/coding/thinking-in-java/2128.html | 边城网事