Java进阶篇--读写锁

目录

读写锁的介绍

写锁的获取及释放

读锁的获取及释放

锁降级

代码示例


读写锁的介绍

读写锁是用于解决读多写少场景下线程安全问题的一种机制。在并发环境中,当多个线程同时读取共享数据时,使用读写锁可以允许多个线程同时获取读锁,提高读取效率;而当某个线程需要更新共享数据时,需要获取写锁,此时所有的读线程和其他写线程都会被阻塞,保证数据的一致性。

读写锁由Java中的ReentrantReadWriteLock实现,其特性包括:

1. 公平性选择:支持非公平性(默认)和公平性的锁获取方式。非公平锁的吞吐量较高。
2. 重入性:支持重入,即同一个线程可以多次获取读锁或写锁,避免死锁。
3. 锁降级:遵循获取写锁、获取读锁再释放写锁的顺序,写锁可以降级为读锁,提升并发性能。
4. 写锁互斥:写锁之间、写锁与读锁之间以及读锁与读锁之间都是互斥的,保证了数据的一致性。

读写锁适用于读操作频繁、写操作较少的情况,例如数据库查询操作。读写锁的使用可以提高程序的并发读取能力,减少读操作之间的互斥等待,从而提高程序的性能和响应速度。

总的来说,读写锁是一种针对读多写少场景的优化手段,通过允许多个线程同时读取共享数据,提高了程序的并发读取效率。但是需要注意合理使用,避免滥用读锁导致写线程无法及时更新共享资源。

写锁的获取及释放

Java中的写锁是通过ReentrantReadWriteLock类实现的。它允许多个线程同时读取共享资源,但在写操作时需要获取独占的写锁。

下面是Java写锁的获取及释放的详细过程:

1、获取写锁:

  • 通过创建一个ReentrantReadWriteLock对象来创建读写锁。
  • 调用writeLock()方法获取写锁。如果当前没有线程持有写锁或读锁时,该方法会立即返回写锁。
  • 如果当前有线程持有写锁或有线程正在等待获取写锁,调用writeLock()方法的线程会被阻塞,直到获取到写锁为止。

2、执行写操作:

  • 当获取到写锁后,执行需要独占资源的写操作。

3、释放写锁:

  • 在写操作完成后,调用writeLock()方法返回的写锁对象的unlock()方法释放写锁。
  • 这样其他等待获取写锁的线程就可以继续执行。

需要注意的是,在获取写锁后,其他线程无法同时获取读锁或写锁。这是为了保证写操作的原子性和一致性。

以下是一个示例代码,演示了如何使用Java的写锁:

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class main {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); // 创建读写锁对象
    private int data = 0; // 共享数据

    public void writeData(int newValue) {
        lock.writeLock().lock(); // 获取写锁
        try {
            // 执行写操作
            data = newValue;
            System.out.println("写入数据: " + data);
        } finally {
            lock.writeLock().unlock(); // 释放写锁
        }
    }
}

读锁的获取及释放

Java中的读锁是通过ReentrantReadWriteLock类实现的。读锁允许多个线程同时读取共享资源,但在写操作时需要排斥其他线程的读操作和写操作。

下面是Java读锁的获取及释放的详细过程:

1、获取读锁:

  • 通过创建一个ReentrantReadWriteLock对象来创建读写锁。
  • 调用readLock()方法获取读锁。如果当前没有线程持有写锁,并且没有线程正在等待获取写锁,该方法会立即返回读锁。
  • 如果当前有线程持有写锁或有线程正在等待获取写锁,调用readLock()方法的线程会被阻塞,直到获取到读锁为止。

2、执行读操作:

  • 当获取到读锁后,执行需要读取共享资源的操作。

3、释放读锁:

  • 在读操作完成后,调用readLock()方法返回的读锁对象的unlock()方法释放读锁。
  • 如果没有其他线程在等待写锁,那么此时读锁将被释放,其他线程可以继续获取读锁进行读操作。

需要注意的是,读锁与写锁是互斥的,即当存在一个线程持有写锁时,其他线程无法同时获取读锁或写锁。这是为了保证数据的一致性和避免竞态条件。

以下是一个示例代码,演示了如何使用Java的读锁:

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class main {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); // 创建读写锁对象
    private int data = 0; // 共享数据

    public void readData() {
        lock.readLock().lock(); // 获取读锁
        try {
            // 执行读操作
            System.out.println("读取数据: " + data);
        } finally {
            lock.readLock().unlock(); // 释放读锁
        }
    }
}

锁降级

锁降级是指将持有写锁的线程获取读锁后再释放写锁的过程。这样可以在保持数据一致性的同时,允许其他线程同时进行读操作,提高并发性能。

Java中的ReentrantReadWriteLock类支持锁降级。按照锁降级的规则,持有写锁的线程可以首先获取读锁,然后再释放写锁,以将写锁降级为读锁,不支持锁升级。

例如,以下是一个示例代码,演示了锁降级的过程:

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class main {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); // 创建读写锁对象
    private int data = 0; // 共享数据

    public void processData() {
        lock.writeLock().lock(); // 获取写锁
        try {
            // 执行数据处理操作
            data++;
            System.out.println("数据处理完成,当前值为: " + data);

            // 锁降级:获取读锁
            lock.readLock().lock();
        } finally {
            lock.writeLock().unlock(); // 释放写锁
        }

        try {
            // 执行读操作
            System.out.println("读取数据: " + data);
        } finally {
            lock.readLock().unlock(); // 释放读锁
        }
    }
}

在上述示例代码中,我们首先获取写锁,执行数据处理操作,然后通过获取读锁实现锁降级。最后,在释放写锁之前,执行读操作。

需要注意的是,锁降级是允许的,因为读锁是共享的,多个线程可以同时持有读锁。但是,锁升级是不支持的,即在持有读锁的情况下,无法直接获取写锁。

通过锁降级,我们能够在保持数据一致性的同时,允许其他线程进行读操作,提高了并发性能。这是读写锁的一个重要特性。

代码示例

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class main {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); // 创建读写锁对象
    private int data = 0; // 共享数据

    public void processData() {
        lock.writeLock().lock(); // 获取写锁
        try {
            // 执行复杂的数据处理操作
            System.out.println("执行复杂的数据处理操作...");

            // 模拟耗时的数据处理操作
            Thread.sleep(2000);

            data++;
            System.out.println("数据处理完成,当前值为: " + data);

            // 锁降级:获取读锁
            lock.readLock().lock();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock(); // 释放写锁
        }

        try {
            // 执行读操作
            System.out.println("读取数据: " + data);
        } finally {
            lock.readLock().unlock(); // 释放读锁
        }
    }

    public static void main(String[] args) {
        main example = new main();

        // 写数据示例
        new Thread(() -> {
            example.processData();
        }).start();

        // 读数据示例
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                example.processData();
            }).start();
        }
    }
}

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在奋斗的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值