面试题: java中的悲观锁和乐观锁

目的

方便后续自己复习方便, 也是一次学习的记录.

资源

B站的一个讲高频面试题的一个学习视频

悲观锁

synchronized 和 LOCK 锁
① 其核心思想是: 线程只有占有了锁, 才能去操作共享变量, 每次只有一个线程占锁成功, 获取锁失败的线程, 都得停下来等待.
② 线程从运行到阻塞、再从阻塞到唤醒, 涉及线程上下文切换, 如果频繁发生, 影响性能.
③ 实际上, 线程在获取synchronized和Lock锁时, 如果锁已被占用, 都会做几次重试操作, 减少阻塞的机会

乐观锁

AtomicInteger 使用 CAS 来保证原子性
① 其核心思想是: 无需加锁, 每次只有一个线程能成功修改共享变量, 其他失败的线程不需要停止, 不断重试直至成功.
② 由于线程一直运行, 不需要阻塞, 因此不涉及线程上下文切换.
③ 它需要多核CPU支持, 且线程数不超过CPU核数

代码演示

/**
 * 悲观锁和乐观锁区别
 * <p>
 * Setting -> Java Compiler -> Override compiler parameters pre-module
 * --add-exports=java.base/jdk.internal.access=ALL-UNNAMED
 * --add-exports=java.base/jdk.internal=ALL-UNNAMED
 * --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED
 *
 * @author xiaozhengN [email protected]
 * @since 2022-11-20 16:55:07
 **/
@Slf4j
public class SyncVsCas {
    
    

    static final Unsafe UNSAFE = Unsafe.getUnsafe();

    static final long BALANCE = UNSAFE.objectFieldOffset(Account.class, "balance");

    /**
     * 账户对象
     */
    @Data
    @Builder
    static class Account {
    
    
        // 账户余额
        volatile int balance;
    }

    // 悲观锁例子
    private static void sync(Account account) {
    
    
        new Thread(() -> {
    
    
            synchronized (account) {
    
    
                int oldValue = account.balance;
                int newValue = oldValue + 5;
                account.balance = newValue;
            }
        }).start();
        new Thread(() -> {
    
    
            synchronized (account) {
    
    
                int oldValue = account.balance;
                int newValue = oldValue - 5;
                account.balance = newValue;
            }
        }).start();
        log.info("账户余额: " + account.balance);
    }

    // 乐观锁例子
    private static void cas(Account account) {
    
    
        new Thread(() -> {
    
    
            while (true) {
    
    
                int oldValue = account.balance;
                int newValue = oldValue + 5;
                // 比较交换
                if (UNSAFE.compareAndSetInt(account, BALANCE, oldValue, newValue)) {
    
    
                    break;
                }
            }
        }).start();
        new Thread(() -> {
    
    
            while (true) {
    
    
                int oldValue = account.balance;
                int newValue = oldValue - 5;
                // 比较交换
                if (UNSAFE.compareAndSetInt(account, BALANCE, oldValue, newValue)) {
    
    
                    break;
                }
            }
        }).start();
        log.info("账户余额: " + account.balance);
    }

    public static void main(String[] args) {
    
    
        sync(Account.builder().balance(10).build());
        cas(Account.builder().balance(10).build());
    }
}

猜你喜欢

转载自blog.csdn.net/xiaozhengN/article/details/127950870