java中的锁

210 阅读3分钟

java中的有很多锁,下面归纳总结介绍一下

  1. 线程要不要锁住同步资源: 1) 悲观锁 2)乐观锁
  2. 多线程能否共享一把锁 : 1)共享锁 2)独占锁
  3. 多线程竞争时,是否需要排队 : 1)公平锁 2)非公平锁
  4. 同一个线程是否可以重复获取同一把锁 :1)可重入 2)不可重入
  5. 是否可中断:1)可中断锁 2)不可中断锁
  6. 等锁的过程: 1) 自旋锁 2)非自旋锁

1. 悲观锁和乐观锁

①悲观锁 :认为我不锁住这个资源,别人就会来争抢。为了保证数据准确性,会在每次获取修改数据时候,把数据锁住,让别人无法访问该数据,这样就保证了数据的准确性。 synchronizedLock相关类都属于悲观锁。

②乐观锁 :认为自己在处理操作的时候不会有其他线程来干扰,不会锁住 正在操作的对象,在更新的时候,对比修改之前的数据有没有改变,如果没被改变,就说明只有自己在操作,就正常修改数据。如果和之前的数据不一样,就不继续更新,采取其他操作。 乐观锁实现一般都是利用CAS算法来实现。

2.共享锁和独占锁

① 共享锁:可以称为读锁,获得共享锁之后,可以查看但无法修改和删除数据,其他线程此时也可以获取到共享锁,也可以查看,但无法修改和删除数据。

②独占锁:共享锁和独占锁的就是读写锁ReentrantReadWriteLock,其中读锁是共享锁,写锁是独占锁。

2.1 读写锁的规则
    1. 多个线程申请读锁,都可以申请到
    1. 如果有一个线程已经占用了读锁,此时其他线程如果要申请写锁,则申请写锁的线程会一直等待读锁释放。
    1. 如果有一个线程已经占用了写锁,此时其他线程如果要申请写锁或者读锁,就一直等待释放写锁。
  • 要么一个线程或者多个线程一起读,同时持有读锁,要么一个线程有写锁,读锁和写锁不能同时持有 ,要么多读,要么一写。

3.可重入锁和不可重入锁

① 可重入锁:在获取锁的时候先判断,如果当前线程是已经持有锁的线程,state值+1 ,然后返回true,在释放锁的时候判断当前线程是否是持有锁的线程,然后判断state,state等于0,才真正释放锁。

② 不可重入锁:直接尝试获取锁,释放锁直接将state设置为0。

4.自旋锁和阻塞锁

①自旋锁: 如果加锁的代码块比较简单,线程中锁的状态转换可能比代码执行的时间还要长,为了让当前线程稍等一下,就需要让当前线程自旋,在自旋完成后,前面的锁同步资源的线程已经释放了锁,那么当前线程就可以不必阻塞,直接获取同步资源,从而避免线程切换的开销。(并发不是很高的时候,比阻塞锁效率高) ②阻塞锁: 如果没拿到锁,就直接把线程阻塞,直到被唤醒。

TIPS: AtomicIngter的实现原理就是就是自旋锁+CAS
AtomicIngter调用unsafe进行自增操作的源码中的do-while循环就是一个自旋操作,如果修改过程中遇到其他线程竞争导致没修改成功,就在while里死循环,直至修改成功。

5. 公平锁 和非公平锁 (避免唤醒带来的空档期)

①公平锁:线程获取完锁,就释放,在想拿就继续排队,大家都有执行的机会,很公平。

②非公平锁: 可以插队,在线程中可以继续执行lock,知道所有的线程中所有的资源释放,其他线程才可以获取到锁。

老松原创,转载注明链接。