Java锁

1.锁分类:

1)公平锁/非公平锁
2)可重入锁
3)独享锁/共享锁
4)互斥锁/读写锁
5)乐观锁/悲观锁
6)分段锁
7)偏向锁/轻量级锁/重量级锁
8)自旋锁

2.常见的锁:

  • Synchronized:
    非公平,悲观、独享、互斥、可重入、重量级锁
  • ReentrantLock:
    默认非公平但可实现公平,悲观、独享、互斥、可重入、重量级锁
  • ReentrantReadWriteLock:
    非公平,悲观、写独享、读共享、读写、可重入、重量级锁

3.ReentrantLock与Synchronized的区别:

  • ReentrantLock优势:
  • 原始构成:
    Synchronized关键字属于Jvm层面的,底层基于monitor对象锁实现
    ReentrantLock属于api接口层面,
  • 可中断等待:
    线程A和B都要获取对象的锁,如果线程A先获取了锁,B将等待A释放锁,
    使用synchronized,如果A不释放,B将一直等待下去,不被中断,
    使用ReentrantLock,如果A不释放,B在等待了足够长的时间后,中断等待,去做其它事情
    ReentrantLock获取锁的方式:
    1)lock(),如果获取了锁立即返回,如果别的线程持有锁,当前线程一直休眠,直到获取锁
    2)tryLock(),如果获取了锁,立即返回true(),如果别的线程正持有锁,则立即返回flase
    3)tryck(long timeout, TimeUnit unit),如果当前线程获取了锁,立即返回true,如果别的线程持有锁,等待参数给定时间,等待过程中获取了锁,返回true,超时未获取到锁返回false
  • 可实现公平锁:
    对于ReentrantLock,通过构造函数指定该锁是否是公平锁,默认是非公平锁
  • 可绑定多个条件:
    绑定多个条件是指一个ReentrantLock可以绑定多个Condition对象,在Synchronized锁对象中,锁对象的wait()和notify()、notifyAll()方法可以实现一个隐含条件,如果要和多个条件关联,就需要添加多个Synchronized锁,而ReentrantLock只需要调用new Condition()犯法即可
  • Synchronized优势:
  • 不会产生死锁:
    Synchronized在Jvm层面实现,在代码出现异常时,Jvm会自动释放锁,不会产生死锁
    Lock不行,Lock是基于代码实现的,要保证锁一定会被释放,就必须将锁放到finally()中,且必须保证lock()和unlock()是成对出现的

4.公平锁/非公平锁

  • 公平锁:
    多个线程按照申请锁的顺序来获取锁
    ReentrantLock(true)公平锁,基于AQS来实现线程调度
  • 非公平锁:
    多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程先获取锁
    Synchronized为非公平锁
    ReentrantLock,通过构造函数指定锁手否是公平锁,默认是非公平锁
  • 非公平锁的优点:
    1) 非公平锁的吞吐量比公平锁大
  • 非公平锁的缺点:
    1)线程的优先级反转
    2)线程饥饿

5.乐观锁/悲观锁

  • 悲观锁:
    悲观锁认为对于同一个事务的并发操作,一定是会发生修改的,哪怕是没有发生修改,因此对于同一个数据的并发操作,悲观锁采用加锁的形式
    悲观锁在Java中的使用,就是各种锁的使用
  • 乐观锁:
    乐观锁认为对同一个事务的并发操作,是不会发生修改的,在更新数据的时候,会采用尝试更新的方式,不断尝试的方式更新数据
    乐观锁在Java中使用,就是无锁编程,如CAS算法

6.独享锁/共享锁

  • 独享锁:
    独享锁指该锁一次只能被一个线程持有
    ReentrantLock、Synchronized是独享锁
  • 共享锁:
    共享锁指锁被多个线程持有
    ReentrantReadWriteLock其读锁是共享锁,写锁是独享锁
    共享锁的并发是非常高的

7.互斥锁/读写锁

独享锁/共享锁是一种广义上的说法,互斥锁/读写锁就是具体实现,
ReentrantLock是互斥锁
ReentrantReadWriteLock是读写锁

8.可重入锁

  • 可重入锁又名递归锁,是指同一个线程在外层获取锁的时候,再次进入内层方法会自动获取锁。
    ReentrantLock是一个可重入锁,Synchronized在优化后也算可重入锁(偏向锁)

9.分段锁

  • 分段锁是一种设计,并不是锁
    对于ConcurrentHashMap而言,其通过分段锁的形式实现高效并发操作,
    ConcurrentHashMap中的分段锁称为Segment,它类似于HashMap的结构,内部拥有一个Entry数组,数组中的每个元素是一个链表,同时又是一个ReentrantLock(Seggment集成了ReentrantLock)
    当put元素时,不对整个map加锁,先通过HashCode直到它放在哪一个分段中,然后对这个分段加锁,所以多线程中,只要不在一个分段,就实现了真正的并行插入

10.自旋锁

  • 尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗

你可能感兴趣的:(Java,Java锁)