Java——锁
Java中的锁
什么是锁
在计算机科学中,锁(lock)与互斥(mutex)是一种同步机制,用于在许多线程执行时对资源的限制。
锁通常需要硬件支持才可以有效实施。这种支持通常采用一个或多个原子指令,测试单个线程是否空闲。
锁的三个概念
- 锁开销:就是完成一个锁可能额外耗费的资源,比如一个周期所需要的时间,内存空间。
- 锁竞争:一个线程或进程,要获取另一个线程或进程所持有的锁,边会发生锁竞争。锁粒度越小,竞争的可能约小。
- 死锁:多线程以及多进程改善了系统资源的利用率并提高了系统的处理能力。然而,并发执行也带来了新的问题——死锁。所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。
锁的分类
乐观锁与悲观锁
1.乐观锁,每次拿数据的时候认为别人都不会修改,在更新的时候再判断在此期间有没有更新数据,可以使用版本号等机制,适合读取多场景,提高性能。
2.悲观锁,每次拿数据都认为别人会修改,都会上锁,可以使用synchronized、独占锁Lock、读写锁等机制,适合写多的场景,保证写入操作正确。
自旋锁与适应性自旋锁
- 自旋锁:指当一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断判断锁是否能获取成功,直到获取到锁才退出循环。
优点:线程不进行上下文切换,减少了上下文切换的时间。
存在的问题:如果线程持有锁的时间较长,其他线程进入循环,消耗cpu。 - 自适应自旋锁:指的是自旋的时间不固定,由前一个在同一个锁上自旋的时间和锁拥有者的状态来决定。如果在同一个对象上,刚刚通过自旋成功获取过锁,且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋很有可能再次成功。反之自旋操作很少成功获取锁,那么后面获取这个锁可能直接省略掉自旋的过程,直接阻塞线程。
公平锁与非公平锁
- 公平锁是指多个线程按照申请锁的顺序直接进入队列排队,队列中的第一个线程才能获取锁。
- 非公平锁是指线程先尝试获取锁,获取不到进入队列中排队,如果能获取到,则无需阻塞直接获取锁。
重入锁与非重入锁
重入锁:同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁,前提是锁对象是相同的。
共享锁与排他锁
- 共享锁是指一个锁可以被多个线程锁持有。
- 排它锁或者叫独享锁或者互斥锁 指锁一次只能被一个线程所持有。
读写锁
- 读锁是共享的,写锁是独占的。
- 读读之间不会互斥,读写互斥,写写互斥,读写锁提高了读的性能。
死锁
死锁的定义
多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而,并发执行也带来了新的问题——死锁。
所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。
死锁产生的原因
可归结为如下两点:
a. 竞争资源
系统中的资源可以分为两类:
- 可剥夺资源,是指某进程在获得这类资源后,该资源可以再被其他进程或系统剥夺,CPU和主存均属于可剥夺性资源(例如:系统中只有一台打印机,可供进程P1使用,假定P1已占用了打印机,若P2继续要求打印机打印将阻塞);
- 不可剥夺资源,当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如磁带机、打印机等。
b. 进程间推进顺序非法
- 若P1保持了资源R1,P2保持了资源R2,系统处于不安全状态,因为这两个进程再向前推进,便可能发生死锁
- 例如,当P1运行到P1:Request(R2)时,将因R2已被P2占用而阻塞;当P2运行到P2:Request(R1)时,也将因R1已被P1占用而阻塞,于是发生进程死锁。
死锁产生的4个必要条件
产生死锁的必要条件:
- 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
- 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
- 环路等待条件:在发生死锁时,必然存在一个进程–资源的环形链。
死锁的处理方法
预防
- 破坏”请求与保持"条件:第一种方法静态分配即每个进程在开始执行时就申请他所需要的全部资源。第二种是动态分配即每个进程在申请所需要的资源时他本身不占用系统资源。
- 破坏“不可剥夺”条件:一个进程不能获得所需要的全部资源时便处于等待状态,等待期间他占有的资源将被隐式的释放重新加入到系统的资源列表中,可以被其他的进程使用,而等待的进程只有重新获得自己原有的资源以及新申请的资源才可以重新启动,执行。
- 破坏“循环等待”条件:采用资源有序分配其基本思想是将系统中的所有资源顺序编号,将紧缺的,稀少的采用较大的编号,在申请资源时必须按照编号的顺序进行,一个进程只有获得较小编号的进程才能申请较大编号的进程。
避免
- 系统处于安全状态(存在能让所有进程执行完的序列),可避免死锁
- 系统处于不安全状态,可能进入死锁状态(银行家算法)
检测
资源分配图不可完全简化,则是死锁状态
解除
处理抢占资源 / 终止死锁进程