比较ReentrantLock和synchronized和信号量Semaphore实现的同步性能

来源:互联网 发布:纽约大学商学院知乎 编辑:程序博客网 时间:2024/05/17 10:42

比较ReentrantLock和synchronized和信号量Semaphore实现的同步性能

得出结论:

(1)使用Lock的性能比使用synchronized关键字要提高4~5倍;

(2)使用信号量实现同步的速度大约比synchronized要慢10~20%;

(3)使用atomic包的AtomicInter速度是比Lock要快1一个数量级。

synchronized:
在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。
ReentrantLock:
ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。
Atomic:
和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。

ReentrantLock 类
java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java 类,而不是作为语言的特性来实现。这就为 Lock 的多种实现留下了空间,各种实现可能有不同的调度算法、性能特性或者锁定语义。ReentrantLock类实现了 Lock,它拥有与 synchronized 相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。(换句话说,当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上。)

reentrant 锁意味着什么呢?简单来说,它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放。这模仿了 synchronized的语义;如果线程进入由线程已经拥有的监控器保护的 synchronized块,就允许线程继续进行,当线程退出第二个(或者后续)synchronized 块的时候,不释放锁,只有线程退出它进入的监控器保护的第一个 synchronized块时,才释放锁。

在查看清单 1 中的代码示例时,可以看到 Lock 和 synchronized 有一点明显的区别 —— lock 必须在 finally 块中释放。否则,如果受保护的代码将抛出异常,锁就有可能永远得不到释放!这一点区别看起来可能没什么,但是实际上,它极为重要。忘记在 finally 块中释放锁,可能会在程序中留下一个定时bomb,当有一天bomb爆炸时,您要花费很大力气才有找到源头在哪。而使用同步,JVM 将确保锁会获得自动释放。

public abstract class Test {

         protected String id;

         protectedCyclicBarrier barrier;

         protected longcount;

         protected intthreadNum;

         protectedExecutorService executor;

         public Test(Stringid, CyclicBarrier barrier, long count, int threadNum,

                            ExecutorServiceexecutor) {

                   this.id =id;

                   this.barrier= barrier;

                   this.count= count;

                   this.threadNum= threadNum;

                   this.executor= executor;

         }

         public voidstartTest() {

                   long start= System.currentTimeMillis();

                   for (int j= 0; j < threadNum; j++) {

                            executor.execute(newThread() {

                                     @Override

                                     publicvoid run() {

                                               for(int i = 0; i < count; i++) {

                                                        test();

                                               }

                                               try{

                                                        barrier.await();

                                              } catch (InterruptedException e) {

                                                        e.printStackTrace();

                                               }catch (BrokenBarrierException e) {

                                                        e.printStackTrace();

                                               }

                                     }

                            });

                   }

                   try {

                            barrier.await();

                   } catch(InterruptedException e) {

                            e.printStackTrace();

                   } catch (BrokenBarrierExceptione) {

                            e.printStackTrace();

                   }

                   // 所有线程执行完成之后,才会跑到这一步

                   longduration = System.currentTimeMillis() - start;

                   System.out.println(id+ " = " + duration);

         }

         protected abstractvoid test();

}

 

测试类ReentreLockTest 源码

import thread.test.Test;

public class ReentreLockTest {

         private static longCOUNT = 1000000;

         private static Locklock = new ReentrantLock();

         private static longlockCounter = 0;

         private static longsyncCounter = 0;

         private static longsemaCounter = 0;

         private staticAtomicLong atomicCounter = new AtomicLong(0);

         private staticObject syncLock = new Object();

         private staticSemaphore mutex = new Semaphore(1);

         public static voidtestLock(int num, int threadCount) {

         }

         static longgetLock() {

                   lock.lock();

                   try {

                            returnlockCounter;

                   } finally{

                            lock.unlock();

                   }

         }

         static longgetSync() {

                   synchronized(syncLock) {

                            returnsyncCounter;

                   }

         }

         static longgetAtom() {

                   returnatomicCounter.get();

         }

         static longgetSemaphore() throws InterruptedException {

                   mutex.acquire();

                   try {

                            returnsemaCounter;

                   } finally{

                            mutex.release();

                   }

         }

         static longgetLockInc() {

                   lock.lock();

                   try {

                            return++lockCounter;

                   } finally{

                            lock.unlock();

                   }

         }

         static longgetSyncInc() {

                   synchronized(syncLock) {

                            return++syncCounter;

                   }

         }

         static longgetAtomInc() {

                   returnatomicCounter.getAndIncrement();

         }

         static classSemaTest extends Test {

                   publicSemaTest(String id, CyclicBarrier barrier, long count,

                                     intthreadNum, ExecutorService executor) {

                            super(id,barrier, count, threadNum, executor);

                   }

                   @Override

                   protectedvoid test() {

                            try{

                                     getSemaphore();

                            }catch (InterruptedException e) {

                                     e.printStackTrace();

                            }

                   }

         }

         static classLockTest extends Test {

                   public LockTest(Stringid, CyclicBarrier barrier, long count,

                                     intthreadNum, ExecutorService executor) {

                            super(id,barrier, count, threadNum, executor);

                   }

                   @Override

                   protectedvoid test() {

                            getLock();

                   }

         }

         static classSyncTest extends Test {

                   publicSyncTest(String id, CyclicBarrier barrier, long count,

                                     intthreadNum, ExecutorService executor) {

                            super(id,barrier, count, threadNum, executor);

                   }

                   @Override

                   protectedvoid test() {

                            getSync();

                   }

 

         }

         static classAtomicTest extends Test {

                   publicAtomicTest(String id, CyclicBarrier barrier, long count,

                                     intthreadNum, ExecutorService executor) {

                            super(id,barrier, count, threadNum, executor);

                   }

                   @Override

                   protectedvoid test() {

                            getAtom();

                   }

         }

         public static void test(Stringid, long count, int threadNum,

                            ExecutorServiceexecutor) {

                   finalCyclicBarrier barrier = new CyclicBarrier(threadNum + 1,

                                     newThread() {

                                               @Override

                                               publicvoid run() {

                                               }

                                     });

                   System.out.println("==============================");

                   System.out.println("count= " + count + "/t" + "Thread Count = "

                                     +threadNum);

                   newLockTest("Lock ", barrier, COUNT, threadNum, executor).startTest();

                   newSyncTest("Sync ", barrier, COUNT, threadNum, executor).startTest();

                   newAtomicTest("Atom ", barrier, COUNT, threadNum, executor)

                                     .startTest();

                   newSemaTest("Sema ", barrier, COUNT, threadNum, executor)

                                     .startTest();

                   System.out.println("==============================");

         }

         public static voidmain(String[] args) {

                   for (int i= 1; i < 5; i++) {

                            ExecutorServiceexecutor = Executors.newFixedThreadPool(10 * i);

                            test("",COUNT * i, 10 * i, executor);

                   }

         }

}

结果

==============================

count = 1000000      ThreadCount = 10

Lock  = 953

Sync  = 3781

Atom  = 78

Sema  = 4922

==============================

==============================

count = 2000000      ThreadCount = 20

Lock  = 1906

Sync  = 8469

Atom  = 172

Sema  = 9719

==============================

==============================

count = 3000000      ThreadCount = 30

Lock  = 2890

Sync  = 12641

Atom  = 219

Sema  = 15015

==============================

==============================

count = 4000000      ThreadCount = 40

Lock  = 3844

Sync  = 17141

Atom  = 343

Sema  = 19782

 

 

 

 

 

 

 

package test.thread;

import static java.lang.System.out;

import java.util.Random;

import java.util.concurrent.BrokenBarrierException;

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.ReentrantLock;

 

public class TestSyncMethods {

         public static voidtest(int round,int threadNum,CyclicBarrier cyclicBarrier){

                   newSyncTest("Sync",round,threadNum,cyclicBarrier).testTime();

                   newLockTest("Lock",round,threadNum,cyclicBarrier).testTime();

                   newAtomicTest("Atom",round,threadNum,cyclicBarrier).testTime();

         }

         public static voidmain(String args[]){

                  

                   for(inti=0;i<5;i++){

                            intround=100000*(i+1);

                            intthreadNum=5*(i+1);

                            CyclicBarriercb=new CyclicBarrier(threadNum*2+1);

                            out.println("==========================");

                            out.println("round:"+round+"thread:"+threadNum);

                            test(round,threadNum,cb);

                           

                   }

         }

}

 

class SyncTest extends TestTemplate{

         publicSyncTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){

                   super(_id, _round, _threadNum, _cb);

         }

         @Override

         /**

          * synchronized关键字不在方法签名里面,所以不涉及重载问题

          */

         synchronizedlong  getValue() {

                   returnsuper.countValue;

         }

         @Override

         synchronizedvoid  sumValue() {

                   super.countValue+=preInit[index++%round];

         }

}

 

class LockTest extends TestTemplate{

         ReentrantLocklock=new ReentrantLock();

         publicLockTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){

                   super(_id, _round, _threadNum, _cb);

         }

         /**

          * synchronized关键字不在方法签名里面,所以不涉及重载问题

          */

         @Override

         long getValue() {

                   try{

                            lock.lock();

                            returnsuper.countValue;

                   }finally{

                            lock.unlock();

                   }

         }

         @Override

         void sumValue() {

                   try{

                            lock.lock();

                            super.countValue+=preInit[index++%round];

                   }finally{

                            lock.unlock();

                   }

         }

}

 

class AtomicTest extends TestTemplate{

         publicAtomicTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){

                   super(_id, _round, _threadNum, _cb);

         }

         @Override

         /**

          * synchronized关键字不在方法签名里面,所以不涉及重载问题

          */

    long  getValue() {

                   returnsuper.countValueAtmoic.get();

         }

         @Override

         void  sumValue() {

                   super.countValueAtmoic.addAndGet(super.preInit[indexAtomic.get()%round]);

         }

}

abstract class TestTemplate{

         private String id;

         protected int round;

         private intthreadNum;

         protected longcountValue;

         protected AtomicLongcountValueAtmoic=new AtomicLong(0);

         protected int[]preInit;

         protected int index;

         protectedAtomicInteger indexAtomic=new AtomicInteger(0);

         Random r=newRandom(47);

         //任务栅栏,同批任务,先到达wait的任务挂起,一直等到全部任务到达制定的wait地点后,才能全部唤醒,继续执行

         privateCyclicBarrier cb;

         publicTestTemplate(String _id,int _round,int _threadNum,CyclicBarrier _cb){

                   this.id=_id;

                   this.round=_round;

                   this.threadNum=_threadNum;

                   cb=_cb;

                   preInit=newint[round];

                   for(inti=0;i<preInit.length;i++){

                            preInit[i]=r.nextInt(100);

                   }

         }

         abstract voidsumValue();

         /*

          * 对long的操作是非原子的,原子操作只针对32位

          * long是64位,底层操作的时候分2个32位读写,因此不是线程安全

          */

         abstract long getValue();

         public voidtestTime(){

                   ExecutorServicese=Executors.newCachedThreadPool();

                   longstart=System.nanoTime();

                   //同时开启2*ThreadNum个数的读写线程

                   for(inti=0;i<threadNum;i++){

                            se.execute(newRunnable(){

                                     publicvoid run() {

                                               for(inti=0;i<round;i++){

                                                        sumValue();

                                               }

                                               //每个线程执行完同步方法后就等待

                                               try{

                                                        cb.await();

                                               }catch (InterruptedException e) {

                                                        //TODO Auto-generated catch block

                                                        e.printStackTrace();

                                               }catch (BrokenBarrierException e) {

                                                        //TODO Auto-generated catch block

                                                        e.printStackTrace();

                                               }

                                     }

                            });

                            se.execute(newRunnable(){

                                     publicvoid run() {

                                               getValue();

                                               try{

                                                        //每个线程执行完同步方法后就等待

                                                        cb.await();

                                               }catch (InterruptedException e) {

                                                        //TODO Auto-generated catch block

                                                        e.printStackTrace();

                                               }catch (BrokenBarrierException e) {

                                                        //TODO Auto-generated catch block

                                                        e.printStackTrace();

                                               }

                                     }

                            });

                   }

                   try {

                            //当前统计线程也wait,所以CyclicBarrier的初始值是threadNum*2+1

                            cb.await();

                   } catch(InterruptedException e) {

                            //TODO Auto-generated catch block

                            e.printStackTrace();

                   } catch(BrokenBarrierException e) {

                            //TODO Auto-generated catch block

                            e.printStackTrace();

                   }

                   //所有线程执行完成之后,才会跑到这一步

                   longduration=System.nanoTime()-start;

                   out.println(id+"= "+duration);

         }

}

原创粉丝点击