Java高频面试题复盘系列之常见锁及原理

124 阅读5分钟

Java高频面试题复盘系列之常见锁及原理

java中锁的种类和基本原理?

synchronized同步锁(对象锁)

     synchronized同步锁(对象锁)
         1 同一时刻, 一个同步锁只能被一个线程访问
         2 以对象为依据,通过synchronized关键字来进行同步,实现对竞争资源的互斥访问
         3 哪个线程先执行带synchronized关键字的方法或synchronized代码块,哪个线程就有该方法或该代码块所持有的锁,其他线程只能呈现等待状态,
             1 前提是多个线程访问同一个对象
         4 synchronized的用途
             1 锁方法
                 1 synchronized修饰普通方法 :在修饰方法的时候默认是当前对象作为锁的对象
                 2 Java中每个对象都有一个锁或者称为监视器,当访问某个对象的synchronized方法时,表示将该对象上锁,而不仅仅是为该方法上锁。
                 3 这样如果一个对象的synchronized方法被某个线程执行时,其他线程无法访问该对象的任何synchronized方法(但是可以调用其他非synchronized的方法)。直至该synchronized方法执行完
                     1 但是如果在synchronized方法中调用的wait方法, 则其他线程能方位该对象的其他synchronized方法
                         1 原因为: 执行wait后会线程会释放自己已经获得的锁
                     2 但如果使用sleep()方法是, 不能访问其他的synchronized方法, sleep不释放锁
             2 静态的synchronized方法调用情况
                 1 使用的锁是synchronized方法所在对象对应的Class对象
                 2 当调用一个对象的静态synchronized方法时,它锁定的并不是synchronized方法所在的对象,而是synchronized方法所在对象对应的Class对象。这样,其他线程就不能调用该类的其他静态synchronized方法了,但是可以调用非静态的synchronized方法
             3 锁代码块
                 1 使用synchronized创建同步代码块: 在修饰代码块的时候需要一个reference对象作为锁的对象.
                 2 synchronized同步代码块只是锁定了该代码块,代码块外面的代码还是可以被访问的, 同样的方法也只是普通的非同步方法
             4 修饰类时候: 在修饰类时候默认是当前类的Class对象作为锁的对象
                 1 即在使用synchronized修饰代码块时, 用"类名.class"作为锁对象
         5 同步锁又成为悲观锁
         6 synchronized关键字不能继承, 即子类中重写的父类的带有synchronized方法后, 子类中的方法不是同步方法, 而是一个普通方法
             1 为什么不能被继承?虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分
         7 注意:
             1 在定义接口方法时不能使用synchronized关键字
             2 构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步
             3 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制
         8 总结
             1 作用于方法时,锁住的是对象的实例(this)
             2 当作用于静态方法时,锁住的是Class实例
             3 synchronized 作用于一个对象实例时,锁住的是所有以该对象为锁的代码块
             4 synchronized 作用于一个class实例时,锁住的是所有以该class为锁的代码块

独占锁(可重入的互斥锁)

     独占锁(可重入的互斥锁)
         1 互斥,即在同一时间点,只能被一个线程持有
         2 可重入,即可以被单个线程多次获取
         3 根据锁的获取机制,它分为“公平锁”和“非公平锁”
             1 Java中通过ReentrantLock实现独占锁,默认为非公平锁

公平锁

     公平锁
         1 是按照通过CLH等待线程按照先来先得的规则, 线程依次排队, 公平的获取锁, 是独占锁的一种
             1 加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得
         2 java中, ReetrantLock中有一个Sync类型的成员变量sync
             1 sync它的实例为FairSync类型的时候,ReetrantLock为公平锁
             2 设置sync为FairSync类型,只需——Lock lock = new ReetrantLock(true)

非公平锁

     非公平锁
         1 是当线程要获取锁时,它会无视CLH等待队列而直接获取锁
             1 加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待
         2 ReetrantLock默认为非公平锁,或Lock lock = new ReetrantLock(false)。

共享锁

     共享锁
         1 能被多个线程同时获取、共享的锁。即多个线程都可以获取该锁,对该锁对象进行处理
         2 典型的就是读锁——ReentrantReadWriteLock.ReadLock
             1 即多个线程都可以读它,而且不影响其他线程对它的读,但是大家都不能修改它
         3 CyclicBarrier, CountDownLatch和Semaphore也都是共享锁

读写锁

     读写锁
         1 维护了一对相关的锁
             1 “读取锁”用于只读操作,它是“共享锁”,能同时被多个线程获取
             2 “写入锁”用于写入操作,它是“独占锁”,只能被一个线程锁获取
         2 读写锁为ReadWriteLock 接口定义,其实现类是ReentrantReadWriteLock,包括内部类ReadLock和WriteLock
             1 方法readLock()、writeLock()分别返回读操作的锁和写操作的锁。

全局锁

     全局锁
         1 实现全局锁有两种方式
             1synchronized关键字用在static方法上
                 1 synchronized加到static静态方法上是对Class类上锁
                 2synchronized加到非static方法上是给对对象上锁, Class锁可以对类的所有对象实例起作用
             2synchronized对类的Class对象进行上锁
                 1 synchronized(class)代码块的作用与synchronized static方法的作用一样