1. 公平锁
- 第一次加锁的时候,他不会去尝试加锁,他会去看一下我前面有没有人排队;
- 如果有人排队,则进入队列(并不等于排队),然后还不死心,再次看一下我有没有拿锁的资格(前面那个人是否为head);
- 如果有资格(前面那个人刚好为head)则继续拿锁,成功则执行同步块;失败则park(排队)。
公平锁第一次加锁,不会初始化队列,也不会进入队列,直接加锁,如果线程之间不发生资源竞争,永远不会初始化队列;
如果发生资源竞争,第二个线程会初始化队列,如果前面是head,还会自旋。
2. 非公平锁
- 首先在lock方法调用加锁的时候就会去抢锁(公平锁调用lock不会上来就拿锁);
- 如果锁没有被人持有,就会去直接加锁(不会判断是否有人排队),成功进入同步块;
- 如果锁被人持有,则加锁失败进入队列;
- 进入队列后如果前面那个人是head则再次尝试加锁,成功则执行同步代码块,失败则park(真正的排队)。
为什么存在队列的情况下,非公平锁可以一上来就抢锁(status=0的情况下),而不是把锁交给队列内的下一个线程?
因为在前一个线程执行结束,将status置为0时,cpu可能已经切换到其他进程,所以还没来得及唤醒队列内的下一个线程。
3. 队列排序
- synchronized实现的锁,如果有多个线程阻塞,唤醒的时候是先进后出
package org.example;
public class TestSysn {
//定义一把锁
private static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
//线程的数量
int N = 10;
Thread[] threads = new Thread[N];
for(int i = 0; i < N; ++i){
threads[i] = new Thread(new Runnable(){
public void run() {
synchronized(lock){
System.out.println(Thread.currentThread().getName() + " get synch lock!");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
synchronized(lock){
for(int i = 0; i < N; ++i){
threads[i].start();
Thread.sleep(200);
}
}
for(int i = 0; i < N; ++i)
threads[i].join();
}
}
- 如果对线程的执行顺序有要求时,可以使用ReentrantLock的公平锁,如果有多个线程阻塞,唤醒的时候是先进先出
- new ReentrantLock(true)公平锁,new ReentrantLock(false)非公平锁,默认是非公平锁
package org.example;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
private static Lock lock = new ReentrantLock(true);
public static void main(String[] args) throws InterruptedException {
int N = 10;
Thread[] threads = new Thread[N];
for(int i = 0; i < N; ++i){
threads[i] = new Thread(new Runnable(){
public void run() {
lock.lock();
System.out.println(Thread.currentThread().getName() + " lock!");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
}
});
}
lock.lock();
for(int i = 0; i < N; ++i){
threads[i].start();
Thread.sleep(200);
}
lock.unlock();
for(int i = 0; i < N; ++i)
threads[i].join();
}
}
4. synchronized是否公平锁
- 是否公平锁得看线程在没有入队之前是否抢锁,入队之后就和公平不公平无关了。
- synchronized是非公平锁