当前位置: 首页 > Thinking in Java > 正文

第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 | 边城网事

该日志由 边城网事 于2015年03月18日发表在 Thinking in Java 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 第21章 – 并发 – 同步机制性能测试(Lock,synchronized,Atomic类)(P749) | 边城网事
关键字: ,

第21章 – 并发 – 同步机制性能测试(Lock,synchronized,Atomic类)(P749) 暂无评论

发表评论

快捷键:Ctrl+Enter