zoukankan      html  css  js  c++  java
  • Lock与synchronized 的区别

    1、ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候
    线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,
    如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
    如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情

    ReentrantLock获取锁定与三种方式:
    a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
    b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
    c)tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
    d) lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断

    2、synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中

    3、在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;

    5.0的多线程任务包对于同步的性能方面有了很大的改进,在原有synchronized关键字的基础上,又增加了ReentrantLock,以及各种Atomic类。了解其性能的优劣程度,有助与我们在特定的情形下做出正确的选择。

    总体的结论先摆出来:

    synchronized: 
    在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。

    ReentrantLock: 
    ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

    Atomic: 
    和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。


    所以,我们写同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化。ReentrantLock和Atomic如果用的不好,不仅不能提高性能,还可能带来灾难。

    先贴测试结果:再贴代码(Atomic测试代码不准确,一个同步中只能有1个Actomic,这里用了2个,但是这里的测试只看速度) 
    ========================== 
    round:100000 thread:5 
    Sync = 35301694 
    Lock = 56255753 
    Atom = 43467535 
    ========================== 
    round:200000 thread:10 
    Sync = 110514604 
    Lock = 204235455 
    Atom = 170535361 
    ========================== 
    round:300000 thread:15 
    Sync = 253123791 
    Lock = 448577123 
    Atom = 362797227 
    ========================== 
    round:400000 thread:20 
    Sync = 16562148262 
    Lock = 846454786 
    Atom = 667947183 
    ========================== 
    round:500000 thread:25 
    Sync = 26932301731 
    Lock = 1273354016 
    Atom = 982564544

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    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位
         * long是64位,底层操作的时候分2个32位读写,因此不是线程安全
         */
        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);
             
        }
     
    }

      

    摘自:

    http://houlinyan.iteye.com/blog/1112535

    http://zzhonghe.iteye.com/blog/826162

  • 相关阅读:
    记录学生的日常
    el表达式与jstl的用法
    学习心得——袁康凯
    学习心得——刘文瑞
    学习心得——高婕
    学习心得——张坤鹏
    Mysql中文乱码 小强斋
    面试题>字符串匹配 小强斋
    选秀节目打分 小强斋
    面试题>字符串匹配 小强斋
  • 原文地址:https://www.cnblogs.com/Ghosgt/p/6475588.html
Copyright © 2011-2022 走看看