Java锁

    xiaoxiao2025-06-09  58

    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.自旋锁

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