公平锁和非公平锁"/>
记录二:公平锁和非公平锁
目录
公平锁和非公平锁概念
案例演示
为何默认非公平锁
应用场景
公平锁和非公平锁的概念
公平锁:是指多个线程按照申请锁的顺序来获取锁,这里类似排队买票,先来的人先买后来的人在队尾排着,这是公平的。如:
Lock lock = new Reentrant(true); //ture表示公平锁,先来先得。
非公平锁:是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁,在高并发环境下,有可能造成优先级翻转或者饥饿的状态(某一个线程一直得不到锁)。如:
Lock lock = new ReentrantLock(false); //false 表示非公平锁,后来的也可能先获得锁
Lock lock = new ReentrantLock();//默认非公平锁
案例演示
import java.util.concurrent.locks.ReentrantLock;class Ticket {//资源类,模拟三个售票员买完30张票private int number = 30;ReentrantLock lock = new ReentrantLock(true);//true 公平锁 ,默认false 非公平锁public void sale() {lock.lock();try {if(number > 0){System.out.println(Thread.currentThread().getName()+ "卖出第:\t" + number-- +"\t 还剩下:" + number);}} finally {lock.unlock();}}
}public class LockTest {public static void main(String[] args) {Ticket ticket = new Ticket();new Thread(() -> {for (int i = 0; i < 55; i++) {ticket.sale();}}, "t1").start();new Thread(() -> {for (int i = 0; i < 55; i++) {ticket.sale();}}, "t2").start();new Thread(() -> {for (int i = 0; i < 55; i++) {ticket.sale();}}, "t3").start();}
}
公平锁结果集:
t1卖出第: 30 还剩下:29
t2卖出第: 29 还剩下:28
t1卖出第: 28 还剩下:27
t2卖出第: 27 还剩下:26
t1卖出第: 26 还剩下:25
t3卖出第: 25 还剩下:24
t2卖出第: 24 还剩下:23
t1卖出第: 23 还剩下:22
t3卖出第: 22 还剩下:21
t2卖出第: 21 还剩下:20
t1卖出第: 20 还剩下:19
t3卖出第: 19 还剩下:18
t2卖出第: 18 还剩下:17
t1卖出第: 17 还剩下:16
t3卖出第: 16 还剩下:15
t2卖出第: 15 还剩下:14
t1卖出第: 14 还剩下:13
t3卖出第: 13 还剩下:12
t2卖出第: 12 还剩下:11
t1卖出第: 11 还剩下:10
t3卖出第: 10 还剩下:9
t2卖出第: 9 还剩下:8
t1卖出第: 8 还剩下:7
t3卖出第: 7 还剩下:6
t2卖出第: 6 还剩下:5
t1卖出第: 5 还剩下:4
t3卖出第: 4 还剩下:3
t2卖出第: 3 还剩下:2
t1卖出第: 2 还剩下:1
t3卖出第: 1 还剩下:0Process finished with exit code 0
非公平锁结果集:
t3卖出第: 30 还剩下:29
t3卖出第: 29 还剩下:28
t3卖出第: 28 还剩下:27
t3卖出第: 27 还剩下:26
t3卖出第: 26 还剩下:25
t3卖出第: 25 还剩下:24
t3卖出第: 24 还剩下:23
t3卖出第: 23 还剩下:22
t3卖出第: 22 还剩下:21
t3卖出第: 21 还剩下:20
t3卖出第: 20 还剩下:19
t3卖出第: 19 还剩下:18
t3卖出第: 18 还剩下:17
t3卖出第: 17 还剩下:16
t1卖出第: 16 还剩下:15
t1卖出第: 15 还剩下:14
t1卖出第: 14 还剩下:13
t1卖出第: 13 还剩下:12
t1卖出第: 12 还剩下:11
t1卖出第: 11 还剩下:10
t1卖出第: 10 还剩下:9
t1卖出第: 9 还剩下:8
t1卖出第: 8 还剩下:7
t1卖出第: 7 还剩下:6
t1卖出第: 6 还剩下:5
t1卖出第: 5 还剩下:4
t1卖出第: 4 还剩下:3
t1卖出第: 3 还剩下:2
t1卖出第: 2 还剩下:1
t1卖出第: 1 还剩下:0Process finished with exit code 0
结论:可以看到公平锁3个线程相对都可以获取到资源,非公平锁只有2个线程有获取到资源,也可能有1个或者3个线程都能获取到资源。
为何默认非公平锁
1.恢复挂起的线程到获取到真正的锁还是有时间差的,从开发人员看这个时间微乎其微,但是从CPU的角度来看,这个时间差存在的还是很明显的。所以非公平锁能更充分的利用CPU的时间片,尽量减少CPU空闲状态时间。
2.使用多线程很重要的考量点线程切换的开销,当采用非公平锁时,当1个线程请求锁获取同步状态,然后释放同步状态,那么刚释放锁的线程在此刻再次获取同步状态的概率就变得非常大,所以就减少了线程的开销。
应用场景
非公平锁:如果系统为了获得更高的吞吐量,很显然非公平锁是比较合适的,因为节省很多线程切换时间的,吞吐量自然就上去了;
公平锁:承上 否则那就用公平锁,大家公平使用
另外思考下:
1.synchronized 是公平锁还是非公平锁呢?案例说明是非公平锁
class SaleShop {//获取食物public void goShop() {System.out.println(Thread.currentThread().getName()+":排队中");synchronized (this) {System.out.println(Thread.currentThread().getName()+":买东西");}}
}
public class SyncLockTest {public static void main(String[] args) {SaleShop saleShop = new SaleShop();//让5个人去购买东东for (int i=0; i<5; i++) {new Thread(saleShop::goShop,"编号:"+(i+1)).start();}}
}
某一次结果:
编号:1:排队中
编号:3:排队中
编号:2:排队中
编号:1:买东西
编号:2:买东西
编号:3:买东西
编号:4:排队中
编号:4:买东西
编号:5:排队中
编号:5:买东西Process finished with exit code 0
总结:排队顺序:1,3,2,4,5 买东西顺序:1,2,3,4,5。第三个人是不是插队了
2.ReentrantLock是如何实现实现公平锁和非公平锁的呢?是基于AbstractQueuedSynchronizer(抽象队列同步器,简称AQS)什么是AQS,下一篇我们继续聊
更多推荐
记录二:公平锁和非公平锁
发布评论