Java锁

Java锁总览:

乐观锁:无锁编程,使用数据版本比较的方法来保证安全性,使用CAS(Compare And Swap)机制。乐观锁假设在大多数情况下不会发生冲突,因此在执行操作时不会加锁,而是在更新数据时检查是否有其他线程修改了数据。

悲观锁:通过synchronized关键字实现。悲观锁假设在任何时候都可能发生冲突,因此在执行操作前会先加锁,以确保数据的一致性。

自旋锁:同样基于CAS机制。自旋锁在尝试获取锁失败后,不会立即进入阻塞状态,而是循环等待一段时间,直到成功获取锁。

可重入锁:由synchronized关键字、ReentrantLock和Lock接口实现。可重入锁允许同一个线程多次获取同一把锁,而不会出现死锁的情况。

读写锁:通过ReentrantReadWriteLock实现。读写锁分为读锁和写锁,允许多个线程同时进行读操作,但写操作是独占的。

公平锁:通过ReentrantLock(true)实现。公平锁保证线程按照请求锁的顺序来获取锁,避免饥饿现象。

非公平锁:通过synchronized关键字和ReentrantLock(false)实现。非公平锁不保证线程获取锁的顺序,可能会导致某些线程长期得不到锁。

共享锁:在ReentrantReadWriteLock中用于读操作。共享锁允许多个线程同时持有读锁,但不允许写操作。

独占锁(排他锁、互斥锁、同步锁):通过synchronized关键字以及ReentrantReadWriteLock中的写锁实现。独占锁在同一时间只允许一个线程持有锁。

重量级锁:由synchronized关键字实现。重量级锁在Java早期版本中会导致线程挂起和唤醒的开销较大,但在JDK 1.6及以后版本中进行了优化。

轻量级锁和偏向锁:属于锁优化技术,用于减少锁的竞争和提升性能。轻量级锁在没有竞争的情况下使用,偏向锁则偏向于让一个线程长时间持有锁。

锁粗化和锁消除:都是锁优化技术,锁粗化是指将短时间的锁合并为长时间的锁,以减少锁的开销;锁消除则是指编译器自动识别并移除不必要的锁操作。


关键字介绍:

CAS(Compare And Swap):

        这是一种硬件指令级别的操作,用于实现乐观锁。它不使用锁,而是通过比较预期值与当前值是否相同来决定是否更新数据。如果不同,则说明数据已经被其他线程修改过,需要重新尝试。

    private AtomicInteger atomicValue = new AtomicInteger(0);
    public void incrementValue() {
        int expectedValue;
        int newValue;
        do {
            // 获取当前值
            expectedValue = atomicValue.get();
            // 计算新值
            newValue = expectedValue + 1;
            // 使用CAS尝试更新值
        } while (!atomicValue.compareAndSet(expectedValue, newValue));

        System.out.println("Updated Value: " + atomicValue.get());
    }

    @Test
    public void CAS() {
        incrementValue(); // 输出:Updated Value: 1
    }

        

synchronized:synchronized关键字-可用于代码块和方法

        是Java中的一种同步机制,可以视为悲观锁。
        可重入锁:允许同一个线程多次获取同一把锁。
        非公平锁:非公平锁允许插队,而公平锁则按照请求的顺序分配锁。
        独占锁/互斥锁:意味着在任何时刻只能有一个线程持有该锁。
        重量级锁:相对于轻量级锁而言,它涉及到操作系统层面的调度,开销较大。

    private int counter = 0; //假设这是共享资源
    private final Object lock = new Object(); // 定义一个锁对象 给synchronized代码块用

    //synchronized代码块
    public void incrementCounterBlock() {
        synchronized (lock) { // 锁定在特定对象上
            counter++;
            System.out.println("Counter incremented to: " + counter);
        }
    }

    //synchronized方法
    public synchronized void incrementCounterMethod() {
        counter++;
        System.out.println("Counter incremented to: " + counter);
    }

    //模拟多线程操作
    @Test
    public void synchronizedTest() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                //incrementCounterMethod();也行
                incrementCounterBlock();
                try {
                    // 让当前线程短暂休眠,模拟实际工作并允许其他线程运行
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                //incrementCounterMethod();也行
                incrementCounterBlock();
                try {
                    // 让当前线程短暂休眠,模拟实际工作并允许其他线程运行
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        t2.start();
        // 等待所有线程完成
        t1.join();
        t2.join();
        System.out.println("Final Counter Value: " + counter);
    }

ReentrantLock:ReentrantLock.lock()和ReentrantLock.unlock(),创建ReentrantLock对象时,true为公平锁,false为非公平锁

        可重入锁:同synchronized一样,支持同一个线程多次获取同一把锁。
        构造函数参数ReentrantLock(boolean fair):当参数为true时,表示创建一个公平锁;false时,默认创建的是非公平锁。

    private int counter = 0; // 共享资源
    private final Lock lock = new ReentrantLock(true); // 创建一个ReentrantLock实例

    public void incrementCounter() {
        lock.lock(); // 获取锁
        try {
            counter++;
            System.out.println(Thread.currentThread().getName() + " incremented counter to: " + counter);
        } finally {
            lock.unlock(); // 确保在操作完成后释放锁
        }
    }

    @Test
    public void lockTest() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                incrementCounter();
                try {
                    // 模拟实际工作负载
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // 恢复中断状态
                }
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                incrementCounter();
                try {
                    // 模拟实际工作负载
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // 恢复中断状态
                }
            }
        });

        t1.start();
        t2.start();
        // 等待所有线程完成
        t1.join();
        t2.join();
        System.out.println("Final Counter Value: " + counter);
    }

ReentrantReadWriteLock:
        读写锁:允许多个读操作并发执行,但写操作是独占的。
        共享锁(读操作):允许多个线程同时读取资源。
        独占锁(写操作):确保在进行写操作时没有其他线程可以访问该资源。

    @Autowired
    private ProjectMapper projectMapper;
    //用于创建 读锁对象、写锁对象
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    //创建 读锁对象
    private final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
    //创建写锁对象
    private final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();

    public Project getProjectById(Long id) {
        readLock.lock();
        try {
            return projectMapper.getProjectById(id);
        } finally {
            readLock.unlock();
        }
    }

    public List<Project> getAllProjects() {
        readLock.lock();
        try {
            return projectMapper.getAllProjects();
        } finally {
            readLock.unlock();
        }
    }

    @Transactional
    public void insertProject(Project project) {
        writeLock.lock();
        try {
            projectMapper.insertProject(project);
        } finally {
            writeLock.unlock();
        }
    }

    @Transactional
    public boolean updateProject(Project project) {
        writeLock.lock();
        try {
            int affectedRows = projectMapper.updateProject(project);
            if (affectedRows == 0) {
                System.out.println("Optimistic locking failed");
                return false;
            }
            return true;
        } finally {
            writeLock.unlock();
        }
    }

        使用 ReentrantReadWriteLock 的读锁(ReadLock)和写锁(WriteLock)是为了控制对共享资源的并发访问。读锁允许多个线程同时持有,只要没有写操作正在进行;而写锁是独占的,当一个线程获取了写锁时,其他任何读或写操作都必须等待。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值