Lock、Synchoronized和ReentrantLock的使用

来源:互联网 发布:梁弯矩计算软件 编辑:程序博客网 时间:2024/06/05 15:00

比较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;

        protected CyclicBarrier barrier;

        protected long count;

        protected int threadNum;

        protected ExecutorService executor;

        public Test(String id, CyclicBarrier barrier, long count, int threadNum,

                           ExecutorService executor) {

                  this.id = id;

                  this.barrier = barrier;

                  this.count = count;

                  this.threadNum = threadNum;

                  this.executor = executor;

        }

        public void startTest() {

                  long start = System.currentTimeMillis();

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

                           executor.execute(new Thread() {

                                    @Override

                                    public void 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 (BrokenBarrierException e) {

                           e.printStackTrace();

                  }

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

                  long duration = System.currentTimeMillis() - start;

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

        }

        protected abstract void test();

}

 

测试类ReentreLockTest源码

import thread.test.Test;

public class ReentreLockTest {

        private static long COUNT = 1000000;

        private static Lock lock = new ReentrantLock();

        private static long lockCounter = 0;

        private static long syncCounter = 0;

        private static long semaCounter = 0;

        private static AtomicLong atomicCounter = new AtomicLong(0);

        private static Object syncLock = new Object();

        private static Semaphore mutex = new Semaphore(1);

        public static void testLock(int num, int threadCount) {

        }

        static long getLock() {

                  lock.lock();

                  try {

                           return lockCounter;

                  } finally {

                           lock.unlock();

                  }

        }

        static long getSync() {

                  synchronized (syncLock) {

                           return syncCounter;

                  }

        }

        static long getAtom() {

                  return atomicCounter.get();

        }

        static long getSemaphore() throws InterruptedException {

                  mutex.acquire();

                  try {

                           return semaCounter;

                  } finally {

                           mutex.release();

                  }

        }

        static long getLockInc() {

                  lock.lock();

                  try {

                           return ++lockCounter;

                  } finally {

                           lock.unlock();

                  }

        }

        static long getSyncInc() {

                  synchronized (syncLock) {

                           return ++syncCounter;

                  }

        }

        static long getAtomInc() {

                  return atomicCounter.getAndIncrement();

        }

        static class SemaTest extends Test {

                  public SemaTest(String id, CyclicBarrier barrier, long count,

                                    int threadNum, ExecutorService executor) {

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

                  }

                  @Override

                  protected void test() {

                           try {

                                    getSemaphore();

                           } catch (InterruptedException e) {

                                    e.printStackTrace();

                           }

                  }

        }

        static class LockTest extends Test {

                  public LockTest(String id, CyclicBarrier barrier, long count,

                                    int threadNum, ExecutorService executor) {

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

                  }

                  @Override

                  protected void test() {

                           getLock();

                  }

        }

        static class SyncTest extends Test {

                  public SyncTest(String id, CyclicBarrier barrier, long count,

                                    int threadNum, ExecutorService executor) {

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

                  }

                  @Override

                  protected void test() {

                           getSync();

                  }

 

        }

        static class AtomicTest extends Test {

                  public AtomicTest(String id, CyclicBarrier barrier, long count,

                                    int threadNum, ExecutorService executor) {

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

                  }

                  @Override

                  protected void test() {

                           getAtom();

                  }

        }

        public static void test(String id, long count, int threadNum,

                           ExecutorService executor) {

                  final CyclicBarrier barrier = new CyclicBarrier(threadNum + 1,

                                    new Thread() {

                                              @Override

                                              public void run() {

                                              }

                                    });

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

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

                                    + threadNum);

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

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

                  new AtomicTest("Atom ", barrier, COUNT, threadNum, executor)

                                    .startTest();

                  new SemaTest("Sema ", barrier, COUNT, threadNum, executor)

                                    .startTest();

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

        }

        public static void main(String[] args) {

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

                           ExecutorService executor = Executors.newFixedThreadPool(10 * i);

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

                  }

        }

}

结果

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

count = 1000000     Thread Count = 10

Lock = 953

Sync = 3781

Atom = 78

Sema = 4922

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

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

count = 2000000     Thread Count = 20

Lock = 1906

Sync = 8469

Atom = 172

Sema = 9719

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

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

count = 3000000     Thread Count = 30

Lock = 2890

Sync = 12641

Atom = 219

Sema = 15015

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

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

count = 4000000     Thread Count = 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 void test(int round,int threadNum,CyclicBarrier cyclicBarrier){

                  new SyncTest("Sync",round,threadNum,cyclicBarrier).testTime();

                  new LockTest("Lock",round,threadNum,cyclicBarrier).testTime();

                  new AtomicTest("Atom",round,threadNum,cyclicBarrier).testTime();

        }

        public static void main(String args[]){

                  

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

                           int round=100000*(i+1);

                           int threadNum=5*(i+1);

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

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

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

                           test(round,threadNum,cb);

                           

                  }

        }

}

 

class SyncTest extends TestTemplate{

        public SyncTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){

                  super( _id, _round, _threadNum, _cb);

        }

        @Override

        /**

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

         */

        synchronized long  getValue() {

                  return super.countValue;

        }

        @Override

        synchronized void  sumValue() {

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

        }

}

 

class LockTest extends TestTemplate{

        ReentrantLock lock=new ReentrantLock();

        public LockTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){

                  super( _id, _round, _threadNum, _cb);

        }

        /**

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

         */

        @Override

        long getValue() {

                  try{

                           lock.lock();

                           return super.countValue;

                  }finally{

                           lock.unlock();

                  }

        }

        @Override

        void sumValue() {

                  try{

                           lock.lock();

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

                  }finally{

                           lock.unlock();

                  }

        }

}

 

class AtomicTest extends TestTemplate{

        public AtomicTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){

                  super( _id, _round, _threadNum, _cb);

        }

        @Override

        /**

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

         */

   long  getValue() {

                  return super.countValueAtmoic.get();

        }

        @Override

        void  sumValue() {

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

        }

}

abstract class TestTemplate{

        private String id;

        protected int round;

        private int threadNum;

        protected long countValue;

        protected AtomicLong countValueAtmoic=new AtomicLong(0);

        protected int[] preInit;

        protected int index;

        protected AtomicInteger indexAtomic=new AtomicInteger(0);

        Random r=new Random(47);

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

        private CyclicBarrier cb;

        public TestTemplate(String _id,int _round,int _threadNum,CyclicBarrier _cb){

                  this.id=_id;

                  this.round=_round;

                  this.threadNum=_threadNum;

                  cb=_cb;

                  preInit=new int[round];

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

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

                  }

        }

        abstract void sumValue();

        /*

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

         * long64位,底层操作的时候分232位读写,因此不是线程安全

         */

        abstract long getValue();

        public void testTime(){

                  ExecutorService se=Executors.newCachedThreadPool();

                  long start=System.nanoTime();

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

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

                           se.execute(new Runnable(){

                                    public void run() {

                                              for(int i=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(new Runnable(){

                                    public void 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();

                  }

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

                  long duration=System.nanoTime()-start;

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

        }

}

原创粉丝点击