公平锁和非公平锁
源码上的分析
按序排队公平锁,就是判断同步队列是否还有先驱节点的存在,如果没有先驱节点才能获取锁;
先占先得非公平锁不会管这些,直接去抢夺占用到同步状态
公平锁多了一个 !hasQueuedPredecessors() 这个方法的判断
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
公平锁源码:
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
非公平锁源码:
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
为什么默认非公平
首先是公平锁多了一个判断方法 会占用更多的时间.非公平锁能更充分的利用cpu的时间片
非公平锁下刚释放锁的线程在此获取同步状态的概率会非常大,这样就减少了线程上下文切换的次数,减少开销,效率就比较高
使用公平锁的问题 怎么选择
会导致锁饥饿的现象,因为排在后面的线程大概率持有不到锁
如果要求吞吐量的话就选择非公平锁 因为开销较低
可重入锁(递归锁)
同一个线程在外层方法获取锁的时候,在进入该线程的内层方法会自动获取锁,不会因为还没释放锁就阻塞住.比如说用synchronized修饰的递归方法. 显式锁一定要记得加锁几次就要解锁几次 否则会导致其他的线程永远无法获取锁
死锁
死锁代码示例:
public class DeadLockDemo {
static Object lockA = new Object();
static Object lockB = new Object();
public static void main(String[] args) {
new Thread(()->{
synchronized (lockA){
System.out.println(Thread.currentThread().getName()+"自己持有a,想去获取b");
try {
TimeUnit.SECONDS.sleep(2L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (lockB){
System.out.println(Thread.currentThread().getName()+"尝试获取b");
}
}
},"a").start();
new Thread(()->{
synchronized (lockB){
try {
TimeUnit.SECONDS.sleep(2L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"自己持有b,想去获取a");
synchronized (lockA){
System.out.println(Thread.currentThread().getName()+"尝试获取a");
}
}
},"b").start();
}
}