Java中具有通过Synchronized实现的内置锁,和ReentrantLock实现的显示锁

  • Synchronized
  • 介绍

    内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码就获得锁,走出相应的代码就释放锁。

     ```
     synchronized(list){ //获得锁
         list.append();
         list.count();
     }//释放锁
     ```
    
     > 与Synchronized配套使用的通信方法通常有wait(),notify()。
     >
     wait()方法会立即释放当前锁,并进入等待状态,等待到相应的notify并重新获得锁过后才能继续执行;notify()不会立刻立刻释放锁,必须要等notify()所在线程执行完synchronized块中的所有代码才会释放。
    
  • 灵活性

     > 
     1. 内置锁在进入同步块时,采取的是无限等待的策略,一旦开始等待,就既不能中断也不能取消,容易产生饥饿与死锁的问题
     2. 在线程调用notify方法时,会随机选择相应对象的等待队列的一个线程将其唤醒,而不是按照FIFO的方式,如果有强烈的公平性要求,比如FIFO就无法满足
    
  • ReentrantLock
  • 介绍

    ReentrantLock是显示锁,需要显示进行 lock 以及 unlock 操作。

     ```
     Lock lock = new ReentrantLock();
     lock.lock();
     try{
        
     }finally{
         lock.unlock();
     }
     ```
    
     > 相比于Synchronized要复杂一些,而且一定要记得在finally中释放锁而不是其他地方,这样才能保证即使出了异常也能释放锁。
    
  • 灵活性

     > 
     1. lock.lockInterruptibly() 可以使得线程在等待锁是支持响应中断;lock.tryLock() 可以使得线程在等待一段时间过后如果还未获得锁就停止等待而非一直等待。有了这两种机制就可以更好的制定获得锁的重试机制,而非盲目一直等待,可以更好的避免饥饿和死锁问题
     2. ReentrantLock可以成为公平锁(非默认的),所谓公平锁就是锁的等待队列的FIFO,不过公平锁会带来性能消耗,如果不是必须的不建议使用。这和CPU对指令进行重排序的理由是相似的,如果强行的按照代码的书写顺序来执行指令,就会浪费许多时钟周期,达不到最大利用率
    

详细秒数可查看 synchronized ReentrantLock