您当前的位置: 首页 > 

Dongguo丶

暂无认证

  • 2浏览

    0关注

    472博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

公平锁非公平锁

Dongguo丶 发布时间:2021-09-16 09:01:21 ,浏览量:2

在Lock锁中案例: 使用非公平锁

实现3个售票员卖出100张票的案例

package com.dongguo.concurrent.synchronize;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Dongguo
 * @date 2021/9/3 0003-10:14
 * @description: 实现3个售票员卖出100张票的案例
 * 使用Lock
 */
public class SaleTicket {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(() -> {
            //循环100次保证能够卖光票
            for (int i = 0; i  {
            for (int i = 0; i  {
            for (int i = 0; i  0) {
                count--;
                System.out.println(Thread.currentThread().getName() + "卖票成功,还剩" + count + "张票!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //解锁
            lock.unlock();
        }
    }
}

运行结果:

T1卖票成功,还剩99张票!
T1卖票成功,还剩98张票!
T1卖票成功,还剩97张票!
T1卖票成功,还剩96张票!
T1卖票成功,还剩95张票!
T1卖票成功,还剩94张票!
T1卖票成功,还剩93张票!
T1卖票成功,还剩92张票!
T1卖票成功,还剩91张票!
T1卖票成功,还剩90张票!
T1卖票成功,还剩89张票!
T1卖票成功,还剩88张票!
T1卖票成功,还剩87张票!
T1卖票成功,还剩86张票!
T1卖票成功,还剩85张票!
T1卖票成功,还剩84张票!
T1卖票成功,还剩83张票!
T1卖票成功,还剩82张票!
T1卖票成功,还剩81张票!
T1卖票成功,还剩80张票!
T1卖票成功,还剩79张票!
T1卖票成功,还剩78张票!
T1卖票成功,还剩77张票!
T1卖票成功,还剩76张票!
T1卖票成功,还剩75张票!
T1卖票成功,还剩74张票!
T1卖票成功,还剩73张票!
T1卖票成功,还剩72张票!
T1卖票成功,还剩71张票!
T1卖票成功,还剩70张票!
T1卖票成功,还剩69张票!
T1卖票成功,还剩68张票!
T1卖票成功,还剩67张票!
T1卖票成功,还剩66张票!
T1卖票成功,还剩65张票!
T1卖票成功,还剩64张票!
T1卖票成功,还剩63张票!
T1卖票成功,还剩62张票!
T1卖票成功,还剩61张票!
T1卖票成功,还剩60张票!
T1卖票成功,还剩59张票!
T1卖票成功,还剩58张票!
T1卖票成功,还剩57张票!
T1卖票成功,还剩56张票!
T1卖票成功,还剩55张票!
T1卖票成功,还剩54张票!
T1卖票成功,还剩53张票!
T1卖票成功,还剩52张票!
T1卖票成功,还剩51张票!
T1卖票成功,还剩50张票!
T1卖票成功,还剩49张票!
T1卖票成功,还剩48张票!
T1卖票成功,还剩47张票!
T1卖票成功,还剩46张票!
T1卖票成功,还剩45张票!
T1卖票成功,还剩44张票!
T1卖票成功,还剩43张票!
T1卖票成功,还剩42张票!
T1卖票成功,还剩41张票!
T1卖票成功,还剩40张票!
T1卖票成功,还剩39张票!
T1卖票成功,还剩38张票!
T1卖票成功,还剩37张票!
T1卖票成功,还剩36张票!
T1卖票成功,还剩35张票!
T1卖票成功,还剩34张票!
T1卖票成功,还剩33张票!
T1卖票成功,还剩32张票!
T1卖票成功,还剩31张票!
T1卖票成功,还剩30张票!
T1卖票成功,还剩29张票!
T1卖票成功,还剩28张票!
T2卖票成功,还剩27张票!
T2卖票成功,还剩26张票!
T2卖票成功,还剩25张票!
T2卖票成功,还剩24张票!
T2卖票成功,还剩23张票!
T2卖票成功,还剩22张票!
T2卖票成功,还剩21张票!
T2卖票成功,还剩20张票!
T2卖票成功,还剩19张票!
T2卖票成功,还剩18张票!
T2卖票成功,还剩17张票!
T2卖票成功,还剩16张票!
T2卖票成功,还剩15张票!
T2卖票成功,还剩14张票!
T2卖票成功,还剩13张票!
T2卖票成功,还剩12张票!
T2卖票成功,还剩11张票!
T2卖票成功,还剩10张票!
T2卖票成功,还剩9张票!
T2卖票成功,还剩8张票!
T2卖票成功,还剩7张票!
T2卖票成功,还剩6张票!
T2卖票成功,还剩5张票!
T2卖票成功,还剩4张票!
T2卖票成功,还剩3张票!
T2卖票成功,还剩2张票!
T2卖票成功,还剩1张票!
T2卖票成功,还剩0张票!

所有的票都被线程t1、t2卖掉了,t3线程没有运行

ReentrantLock既可以是非公平锁,也可以是公平锁

创建ReentrantLock时可以传入一个boolean 值

true为公平锁,false为非公平锁,默认为false是非公平锁

非公平锁有可能出现线程饿死的现象

比如线程t1一直运行,线程t2、线程t3没有获得运行的机会

private final Sync sync;//默认值为false
...
public ReentrantLock() {
    //默认为非公平锁
    sync = new NonfairSync();
}
/**
 * Creates an instance of {@code ReentrantLock} with the
 * given fairness policy.
 *
 * @param fair {@code true} if this lock should use a fair ordering policy
 */
public ReentrantLock(boolean fair) {
    //fair为true 使用公平锁FairSync,为false使用非公平锁NonfairSync
    sync = fair ? new FairSync() : new NonfairSync();
}
使用公平锁
package com.dongguo.sync.saleticket1;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Dongguo
 * @date 2021/8/23 0023-19:19
 * @description: 使用ReentrantLock公平锁
 */
public class Ticket {
    private int number = 100;
    //创建可重入锁ReentrantLock    true为公平锁
    private final ReentrantLock lock = new ReentrantLock(true);

    public void saleTicket() {
        //上锁
        lock.lock();
        if (number > 0) {
            number--;
            System.out.println(Thread.currentThread().getName() + "卖票成功,还剩:" + number + "张");
        }
        //解锁
        lock.unlock();
    }
}

运行结果

T1卖票成功,还剩99张票!
T1卖票成功,还剩98张票!
T1卖票成功,还剩97张票!
T1卖票成功,还剩96张票!
T1卖票成功,还剩95张票!
T1卖票成功,还剩94张票!
T1卖票成功,还剩93张票!
T1卖票成功,还剩92张票!
T1卖票成功,还剩91张票!
T1卖票成功,还剩90张票!
T1卖票成功,还剩89张票!
T1卖票成功,还剩88张票!
T1卖票成功,还剩87张票!
T1卖票成功,还剩86张票!
T1卖票成功,还剩85张票!
T1卖票成功,还剩84张票!
T1卖票成功,还剩83张票!
T1卖票成功,还剩82张票!
T1卖票成功,还剩81张票!
T1卖票成功,还剩80张票!
T1卖票成功,还剩79张票!
T1卖票成功,还剩78张票!
T1卖票成功,还剩77张票!
T1卖票成功,还剩76张票!
T1卖票成功,还剩75张票!
T1卖票成功,还剩74张票!
T1卖票成功,还剩73张票!
T1卖票成功,还剩72张票!
T1卖票成功,还剩71张票!
T1卖票成功,还剩70张票!
T1卖票成功,还剩69张票!
T1卖票成功,还剩68张票!
T1卖票成功,还剩67张票!
T1卖票成功,还剩66张票!
T1卖票成功,还剩65张票!
T1卖票成功,还剩64张票!
T1卖票成功,还剩63张票!
T1卖票成功,还剩62张票!
T1卖票成功,还剩61张票!
T1卖票成功,还剩60张票!
T1卖票成功,还剩59张票!
T1卖票成功,还剩58张票!
T1卖票成功,还剩57张票!
T1卖票成功,还剩56张票!
T1卖票成功,还剩55张票!
T1卖票成功,还剩54张票!
T1卖票成功,还剩53张票!
T1卖票成功,还剩52张票!
T1卖票成功,还剩51张票!
T1卖票成功,还剩50张票!
T1卖票成功,还剩49张票!
T1卖票成功,还剩48张票!
T2卖票成功,还剩47张票!
T1卖票成功,还剩46张票!
T3卖票成功,还剩45张票!
T2卖票成功,还剩44张票!
T1卖票成功,还剩43张票!
T3卖票成功,还剩42张票!
T2卖票成功,还剩41张票!
T1卖票成功,还剩40张票!
T3卖票成功,还剩39张票!
T2卖票成功,还剩38张票!
T1卖票成功,还剩37张票!
T3卖票成功,还剩36张票!
T2卖票成功,还剩35张票!
T1卖票成功,还剩34张票!
T3卖票成功,还剩33张票!
T2卖票成功,还剩32张票!
T1卖票成功,还剩31张票!
T3卖票成功,还剩30张票!
T2卖票成功,还剩29张票!
T1卖票成功,还剩28张票!
T3卖票成功,还剩27张票!
T2卖票成功,还剩26张票!
T1卖票成功,还剩25张票!
T3卖票成功,还剩24张票!
T2卖票成功,还剩23张票!
T1卖票成功,还剩22张票!
T3卖票成功,还剩21张票!
T2卖票成功,还剩20张票!
T1卖票成功,还剩19张票!
T3卖票成功,还剩18张票!
T2卖票成功,还剩17张票!
T1卖票成功,还剩16张票!
T3卖票成功,还剩15张票!
T2卖票成功,还剩14张票!
T1卖票成功,还剩13张票!
T3卖票成功,还剩12张票!
T2卖票成功,还剩11张票!
T1卖票成功,还剩10张票!
T3卖票成功,还剩9张票!
T2卖票成功,还剩8张票!
T1卖票成功,还剩7张票!
T3卖票成功,还剩6张票!
T2卖票成功,还剩5张票!
T1卖票成功,还剩4张票!
T3卖票成功,还剩3张票!
T2卖票成功,还剩2张票!
T1卖票成功,还剩1张票!
T3卖票成功,还剩0张票!

ReentrantLock修改为公平锁 ,每个线程都有运行的机会

创建了的线程轮询获得运行的机会。FIFO

为什么会有公平锁/非公平锁的设计 为什么默认非公平?

1 恢复挂起的线程到真正锁的获取还是有时间差的,从开发人员来看这个时间微乎其微,但是从CPU的角度来看,这个时间差存在的还是很明显的。所以非公平锁能更充分的利用CPU 的时间片,尽量减少 CPU 空闲状态时间。

2 使用多线程很重要的考量点是线程切换的开销,当采用非公平锁时,当1个线程请求锁获取同步状态,然后释放同步状态,因为不需要考虑是否还有前驱节点,所以刚释放锁的线程在此刻再次获取同步状态的概率就变得非常大,所以就减少了线程的开销。

使⽤非公平锁会有什么问题

公平锁保证了排队的公平性,非公平锁霸气的忽视这个规则,所以就有可能导致排队的长时间在排队,也没有机会获取到锁, 这就是传说中的 “锁饥饿”

什么时候用公平?什么时候用非公平?

如果为了更高的吞吐量,很显然非公平锁是比较合适的,因为节省很多线程切换时间,吞吐量自然就上去了; 否则那就用公平锁,大家公平使用。

源码
//默认为非公平锁
public ReentrantLock() {
    sync = new NonfairSync();
}

//fair为true 创建公平锁,为false创建非公平锁
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}
ReentrantLock非公平锁
 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             
关注
打赏
1638062488
查看更多评论
0.3102s