美文网首页
Synchronized和ReentrantLock

Synchronized和ReentrantLock

作者: zxin1 | 来源:发表于2017-04-26 18:18 被阅读0次

    java synchronized知识点

    synchronized相信学过java并发编程的小伙伴一定不会陌生,synchronized用来控制中线程的同步。
    线程安全性:当多个线程同时访问一个类的(对象或者方法),这个类总是表现出正确的行为,则称这个类是线程安全的。

    • synchronized的含义
      1.互斥性
      synchronized用来修饰方法,代码块。
      修饰普通成员方法时,取得的对象锁是调用该方法的对象。
      修饰静态方法时,取得的对象锁是该类的class对象(存在于方jvm的方法区,只有一个)
      修饰代码块的时,对象锁需要开发者自行指定。注意:该对象一定要为共享的,不然线程不安全。
      2.内存可见性
      synchronzied除了互斥的含义之外,还有可见性的含义。
    • synchronized的特性
      1.可重入性
      重入的一种实现方法:为每一个锁关联一个计数值和一个所有者线程。当计数值为0的时候代表该锁不被任何线程持有。当一个线程请求一个未被持有的锁时,JVM将记下锁的持有者,并将计数值加一。当同一个线程再次获取这个锁的时候,计数值递增,当线程退出同步代码块的时候,计数器递减。当为0的时候,这个锁被释放。
      第一个例子:

    public class UseSynchronized {
    public synchronized void method1(){
    System.out.println("进入方法1");
    method2();
    }
    public synchronized void method2(){
    System.out.println("进入方法2");
    method3();
    }
    public synchronized void method3(){
    System.out.println("进入方法3");
    }
    public static void main(String[] args) {
    final UseSynchronized us=new UseSynchronized();
    us.method1();
    }
    }
    第二个例子:java
    public class UseSynchronized {
    private class A{
    public synchronized void test(){
    System.out.println("这是父类的方法");
    }
    }
    class B extends A{
    public synchronized void test(){
    System.out.println("这是子类的方法");
    super.test();
    }
    }
    public static void main(String[] args) {
    B b=new UseSynchronized().new B();
    b.test();
    }
    }
    ```
    2.悲观锁、独占锁
    使用synchronized关键字来保证线程安全性的时候,将会使线程串行化调用方法或者执行代码块。这也就是一些同步类容器例如vector、hashtable效率不高的原因。

    java ReentrantLock知识点

    • ReentrantLock的含义
      1.ReentrantLock与synchronized不同的地方在于它是一种显示锁,需要手动的lock,unlock,它有自己的condition
      2.ReentrantLock也是一种悲观锁

    很多人认为ReentrantLock和synchronized比较,前者性能要比后者性能高很多,其实java1.8以后对synchronized性能进行了优化,使其和ReentrantLock的性能相差不多。

    package org.lock;
    
    import java.util.Random;
    import java.util.concurrent.CyclicBarrier;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    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=5;
        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{
            Random rand=new Random(47);
            for(int i=0;i<SIZE;i++){
                preLoaded[i]=rand.nextInt();
            }
        }
        public abstract void accumulate();
        public abstract long read();
        private class Modifier implements Runnable{
            @Override
            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{
            @Override
            public void run() {
                for(long i=0;i<cycles;i++){
                    value=read();
                }
                try {
                    barrier.await();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } 
            }
        }
        public void timeTest(){
            long start=System.nanoTime();
            for(int i=0;i<N;i++){
                exec.execute(new Modifier());
                exec.execute(new Reader()); 
            }
            try {
                barrier.await();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            duration=System.nanoTime()-start;
            System.out.println(id+"----"+duration);
        }
        public static void report(Accumulator acc1,Accumulator acc2){
            System.out.println(acc1.id+"/"+acc2.id+"="+(double)acc1.duration/(double)acc2.duration);
        }
    }
    class BaseLine extends Accumulator{
        {
            id="BaseLine";
        }
    
        @Override
        public void accumulate() {
            value+=preLoaded[index++];
            if(index>=SIZE){
                index=0;
            }
        }
    
        @Override
        public long read() {
            return value;
        }
    }
    class SynchronizedTest extends Accumulator{
        {
            id="synchronized";
        }
    
        @Override
        public synchronized void accumulate() {
            value+=preLoaded[index++];
            if(index>=SIZE){
                index=0;
            }
        }
    
        @Override
        public synchronized long read() {
            return value;
        }
        
    }
    class LockTest extends Accumulator{
        {
            id="Lock";
        }
        private Lock lock=new ReentrantLock();
        
        @Override
        public void accumulate() {
            lock.lock();
            try{
                value+=preLoaded[index++];
                if(index>=SIZE){
                    index=0;
                }
            }finally{
                lock.unlock();
            }
        }
    
        @Override
        public long read() {
            lock.lock();
            try{
                return value;
            }finally{
                lock.unlock();
            }
        }
    }
    public class SynchronizationComparisons {
        static SynchronizedTest synch=new SynchronizedTest();
        static LockTest lock=new LockTest();
        static void test(){
            System.out.println("==========================");
            System.out.println("Cyccle"+"  "+Accumulator.cycles);
            synch.timeTest();
            lock.timeTest();
            Accumulator.report(synch, lock);
        }
        public static void main(String[] args) {
            int iterations=5;
            if(args.length>0){
                iterations=new Integer(args[0]);
            }
            System.out.println("Warmup");
            for(int i=0;i<iterations;i++){
                test();
                Accumulator.cycles*=2;
            }
            Accumulator.exec.shutdown();
        }
    }
    
    

    运行结果:


    两种锁性能比较.png

    从运行结果可以看出,ReentrantLock性能比Synchronized好一点,但也好不太多。(运行环境:JDK1.8)

    ReentrantLock之所以比synchronized好的地方在于不是它的性能,而是它的多condition,这是synchronized不能比较的。例如ArrayBlockingQueue中就是用的ReentrantLock,里面有两个condition

    condition.png

    总结:并不是所有的地方的都适合用ReentrantLock,具体使用什么要根据生产环境确定。

    相关文章

      网友评论

          本文标题:Synchronized和ReentrantLock

          本文链接:https://www.haomeiwen.com/subject/zbqwzttx.html