Java并发—ReetrantLock详解

news2024/9/27 21:22:50

目录

一、ReetrantLock的特性

1、非阻塞获取锁

2、带超时的锁获取:

3、锁的公平性

4、锁的可中断性

5、Condition条件变量

6、锁的可重入性

可重入锁

不可重入锁

7、性能优化

二、ReentrantLock和Synchronized的区别

1、语法和使用方式

2、锁的获取和释放

3、高级特性

4、条件变量

5、性能

总结

三、ReentrantLock使用场景


之前的文章Java并发—synchronized关键字的应用-CSDN博客讲述了sychronized的应用,那为什么还需要其他的锁呢?

synchronized属于隐式锁,即锁的持有与释放都是隐式的,可能会导致死锁

为了可以灵活地控制锁,就需要使用到显式锁,即锁的持有和释放都必须手动编写

其他锁如 ReentrantLock 提供了更高级的功能,如公平锁、超时等待和可中断等待

在Java 1.5中,官方在concurrent并发包中加入了Lock接口,该接口中提供了lock()方法和unLock()方法对显式加锁和显式释放锁操作进行支持

Lock lock = new ReentrantLock();
 
public void save(){
    try{
        lock.lock();
        //业务代码……
    }finally{
        lock.unlock();
    }
}

从上述代码可以使用ReentrantLock来管理锁,确保在save方法执行期间对资源的独占访问。通过try-finally结构确保即使发生异常也能正确地使用lock.unlock()释放锁 

ReentrantLock实现了Lock接口,Lock接口是Java中对锁操作行为的统一规范

ReentrantLock结构:

一、ReetrantLock的特性

不仅如此,ReetrantLock相对于synchronized解决了很多问题:

上述代码lock.lock();会阻塞当前线程直至获取到锁为止,那么为了避免这个问题就需要使用lock.tryLock()

1、非阻塞获取锁

ReentrantLock提供了tryLock()方法,可以尝试获取锁而不阻塞当前线程。

  • 如果锁当前未被任何线程持有,则tryLock()方法会立即获取锁并返回true。
  • 如果锁当前已被其他线程持有,则tryLock()方法不会阻塞当前线程,而是立即返回false。

代码如下:

     import java.util.concurrent.locks.ReentrantLock;

     public class DemoService {

         //将ReentrantLock实例声明为final可以确保锁对象的不变性,提高线程安全性
         private final ReentrantLock lock = new ReentrantLock();

         public void save() {
             try {
                 lock.lock();
                 // 业务代码……
             } finally {
                 lock.unlock();
             }
         }
     }

2、带超时的锁获取:

ReentrantLock提供了tryLock(long timeout, TimeUnit unit)方法,允许线程在指定时间内尝试获取锁

如果在指定时间内未能获取到锁,则线程不会被阻塞,而是返回false

🌰:多线程获取超时锁的案例

     public class TryLockWithTimeoutExample {

         private final ReentrantLock lock = new ReentrantLock();

         public void save() {
             if (!lock.tryLock(5, TimeUnit.SECONDS)) {
                 // 如果未能在5秒内获取锁,可以记录日志或采取其他措施
                 return; // 或者抛出异常
             }

             try {
                 // 业务代码……
             } catch (Exception e) {
                 // 处理异常
                 throw e;
             } finally {
                 lock.unlock();
             }
         }

         public static void main(String[] args) {
             TryLockWithTimeoutExample example = new TryLockWithTimeoutExample();
             new Thread(example::save).start();
             new Thread(example::save).start();
         }
     }
     

3、锁的公平性

ReentrantLock允许创建公平锁非公平锁

  • 公平锁按照线程请求锁的顺序来分配锁,可以减少线程之间的饥饿现象。保证等待时间最长的线程优先获取锁,其实就是先入队的先得锁,即FIFO
  • 非公平锁不保证请求锁的顺序,可能会让后来的线程优先获取锁

公平锁常见的场景:多线程任务顺序处理、线程池

默认情况下ReentrantLock使用非公平锁

/**
 * 默认创建非公平锁
 */
public ReentrantLock() {
    sync = new NonfairSync();
}

/**
 * fair为true表示是公平锁,fair为false表示是非公平锁
 */
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

🌰:多线程获取公平锁的案例

public class FairReentrantLockExample {

    private final ReentrantLock lock = new ReentrantLock(true); // true 表示公平锁

    public void processTask(int taskId) {
        lock.lock();
        try {
            System.out.println("Processing task " + taskId + " by " + Thread.currentThread().getName());
            // 业务代码……
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        FairReentrantLockExample example = new FairReentrantLockExample();
        
        for (int i = 1; i <= 5; i++) {
            int taskId = i;
            new Thread(() -> example.processTask(taskId)).start();
        }
    }
}

执行顺序:

  • 创建线程:主线程创建5个新线程,每个线程都会调用 processTask(),线程被创建后,它们就会被加入到线程调度器的就绪队列中,等待被调度执行
  • 请求锁
    • 每个线程开始执行时,都会尝试获取锁
    • 由于使用的是公平锁,线程将按照它们请求锁的顺序来获取锁
  • 执行过程
    • 线程1首先调度执行,如果获取到锁开始执行processTask()
    • 其他线程将被阻塞,直至锁可用的状态
    • 线程1执行完执行processTask(),释放锁
    • 线程2请求锁,获取锁开始执行processTask(),此过程将重复,直至所有线程都执行完毕

效果:

Processing task 1 by Thread-0
Processing task 2 by Thread-1
Processing task 3 by Thread-2
Processing task 4 by Thread-3
Processing task 5 by Thread-4

例如:可以使线程池中的线程公平地获取锁,以确保线程按照一定的顺序获取锁,从而避免某些线程长时间无法获取锁导致的饥饿问题

🌰:线程池使用公平锁

     public class FairReentrantLockThreadPoolExample {

         private final ReentrantLock lock = new ReentrantLock(true); // true 表示公平锁
         private final ExecutorService executor = Executors.newFixedThreadPool(3);

         public void processTask(int taskId) {
             lock.lock();
             try {
                 System.out.println("Processing task " + taskId + " by " + Thread.currentThread().getName());
                 // 业务代码……
             } finally {
                 lock.unlock();
             }
         }

         public static void main(String[] args) {
             FairReentrantLockThreadPoolExample example = new FairReentrantLockThreadPoolExample();
             
             for (int i = 1; i <= 5; i++) {
                 int taskId = i;
                 executor.execute(() -> example.processTask(taskId));
             }
             
             // 关闭线程池
             executor.shutdown();
         }
     }
     

说明:在这个例子中,我们创建了一个固定大小的线程池,其中包含3个线程

线程池将处理5个任务,每个任务都需要获取公平锁。由于线程池的大小为3,最多只有3个线程可以同时执行

当一个线程获取锁后,其他线程将被阻塞,直到锁被释放。由于使用了公平锁,线程将按照它们请求锁的顺序来获取锁

4、锁的可中断性

使用ReentrantLock时,线程可以通过中断机制来取消等待锁的操作,避免线程阻塞

lock.lockInterruptibly()获取一个可以被中断的重入锁,允许线程在等待锁的过程中响应中断信号,使用thread.interrupt()可以打断线程

🌰:多线程执行业务时被中断

     public class InterruptibleLockExample {

         private final ReentrantLock lock = new ReentrantLock();
         private final Condition condition = lock.newCondition();

         public void processTask()  {
            try {
                lock.lockInterruptibly();
                System.out.println("Processing task by " + Thread.currentThread().getName());
                // 业务代码……
                // 假设需要等待一段时间
                condition.await(5, TimeUnit.SECONDS);
                System.out.println("Task completed by " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + " interrupted, task cancelled");
            } finally {
                lock.unlock();
                System.out.println(Thread.currentThread().getName() + " released the lock");
            }
        }

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

             Thread thread = new Thread(example::processTask);
             thread.start();

             // 假设我们需要在一段时间后中断线程
             TimeUnit.SECONDS.sleep(2);
             thread.interrupt();
         }
     }
     

线程调用 condition.await(5, TimeUnit.SECONDS) 开始等待 5 秒。在等待过程中,主线程在 2 秒后中断了 Thread-0。Thread-0 在等待过程中被中断,因此将抛出 Interrup如果线程被中断,将抛出 InterruptedException,线程中断退出

效果:

Processing task by Thread-0
Thread-0 interrupted, task cancelled
Thread-0 released the lock

5、Condition条件变量

ReentrantLock支持条件变量,允许线程等待特定条件满足后再继续执行

Condition 接口是 Java 1.5 中引入的 java.util.concurrent 包的一部分,旨在提供更高级别的并发控制,设计目的是为了提供比 wait 和 notify 更加灵活和强大的线程同步机制

Condition 接口允许更细粒度的控制,比如可以有多个条件变量,每个条件变量可以独立使用,从而支持更复杂的同步模式

提供了 awaitsignalsignalAll 等方法。

  • await 方法释放锁并等待,直到被 signal 或 signalAll 方法唤醒。
  • signal 方法唤醒一个等待线程,而 signalAll 方法唤醒所有等待线程。
  • Condition 对象可以与多个锁关联,因此可以实现多个条件变量。

Condition接口可以与ReentrantLock一起使用,提供了更灵活的线程同步机制。

private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();

在上述线程中断的案例中,也使用了Condition的await()

// 假设需要等待5s时间
condition.await(5, TimeUnit.SECONDS);

通过Condition接口定义的方法我们发现跟之前Objectwaitnotify功能几乎差不多,所以使用Condition对象的方法也可以完成线程间的通信

waitnotify 方法:

  • 必须在一个已经同步的对象上调用,即必须在 synchronized 块或方法中使用。
  • wait 方法释放锁并等待,直到被 notify 或 notifyAll 方法唤醒。
  • notify 方法随机唤醒一个等待线程,而 notifyAll 方法唤醒所有等待线程。 只能使用一个同步对象来控制多个线程之间的同步

6、锁的可重入性

锁的可重入性和不可重入性主要描述了一个线程在获取锁之后是否能够再次获取同一把锁而不引起死锁的能力

可重入锁

可重入锁允许一个已经获取了锁的线程再次获取同一把锁,而不会导致其他等待该锁的线程被阻塞

因为可重入锁内部维护了一个计数器,每当同一个线程再次获取锁时,计数器加一;当线程释放锁时,计数器减一,直到计数器为零时,锁才真正被释放

ReentrantLock支持可重入性,即允许已经持有锁的线程再次获取锁。

这种特性在synchronized中也是支持的,但在ReentrantLock中更为明显和可控

🌰:假设一个银行账户需要有存款和取款的操作

先使用synchronized实现重入锁

public class Account {
    private int balance = 0;

    public synchronized void deposit(int amount) {
        balance += amount;
        // 假设我们想在存款后打印余额
        printBalance();
    }

    public synchronized void withdraw(int amount) {
        if (amount <= balance) {
            balance -= amount;
        }
        // 假设我们想在取款后打印余额
        printBalance();
    }

    public synchronized void printBalance() {
        System.out.println("当前余额: " + balance);
    }
}

在这个例子中,deposit 和 withdraw 方法都是同步的,这意味着它们只能由一个线程执行。同样,printBalance 方法也是同步的,这样当一个线程正在执行 deposit 或 withdraw 方法时,它可以安全地调用 printBalance 方法而不会导致死锁

使用ReentrantLock实现重入锁

public class Account {
    private int balance = 0;
    private final ReentrantLock lock = new ReentrantLock();

    public void deposit(int amount) {
        lock.lock();
        try {
            balance += amount;
            // 假设我们想在存款后打印余额
            printBalance();
        } finally {
            lock.unlock();
        }
    }

    public void withdraw(int amount) {
        lock.lock();
        try {
            if (amount <= balance) {
                balance -= amount;
            }
            // 假设我们想在取款后打印余额
            printBalance();
        } finally {
            lock.unlock();
        }
    }

    public void printBalance() {
        lock.lock();
        try {
            System.out.println("当前余额: " + balance);
        } finally {
            lock.unlock();
        }
    }
}

假设初始余额为 0,并且线程 T1 先执行 deposit(100),接着线程 T2 执行 withdraw(50),最后线程 T3 执行 printBalance(),那么输出可能是:

当前余额: 100
当前余额: 50

不可重入锁

不可重入锁不允许一个已经获取了锁的线程再次获取同一把锁,除非它首先释放了锁。如果一个线程试图再次获取锁,它将会被阻塞,直到锁被释放。这种类型的锁通常用于那些不需要支持递归调用的场景

由于 Java 标准库中没有直接提供的不可重入锁实现,我们可以使用 java.util.concurrent.locks.Lock 接口的实现类来模拟一个不可重入锁的行为。这里我们使用 ReentrantLock 并手动管理锁的可重入性

import java.util.concurrent.locks.ReentrantLock;

public class NonReentrantAccount {
    private int balance = 0;
    private ReentrantLock lock = new ReentrantLock();

    public void deposit(int amount) {
        lock.lock();
        try {
            balance += amount;
            // 假设我们想在存款后打印余额
            printBalance();
        } finally {
            lock.unlock();
        }
    }

    public void withdraw(int amount) {
        lock.lock();
        try {
            if (amount <= balance) {
                balance -= amount;
            }
            // 假设我们想在取款后打印余额
            printBalance();
        } finally {
            lock.unlock();
        }
    }

    public void printBalance() {
        // 模拟不可重入锁行为,检查当前线程是否持有锁
        if (!lock.isHeldByCurrentThread()) {
            lock.lock();
            try {
                System.out.println("当前余额: " + balance);
            } finally {
                lock.unlock();
            }
        } else {
            // 如果当前线程已经持有锁,则不打印余额
            // 这里我们简单地跳过打印操作
        }
    }
}

使用 ReentrantLock 来实现锁的功能,但是在 printBalance 方法中,我们检查当前线程是否已经持有锁。如果是,则不执行打印操作,以此来模拟不可重入锁的行为

假设初始余额为 0,并且线程 T1 先执行 deposit(100),接着线程 T2 执行 withdraw(50),最后线程 T3 执行 printBalance(),那么输出可能是:

当前余额: 50

这是因为:

  • 线程 T1 执行 deposit(100),此时T1持有锁,因此 printBalance 不会被执行
  • 线程 T2 执行 withdraw(50),T1释放锁,T2持有锁,因此 printBalance 不会被执行
  • 线程 T3 执行 printBalance(),此时T3不持有锁,因此会先获取锁并打印当前余额 50

⚠️注意:实际应用中很少会使用这样的不可重入锁实现,因为这通常会导致代码难以理解和维护。通常情况下,更倾向于使用可重入锁来避免死锁问题

7、性能优化

ReentrantLock使用了AbstractQueuedSynchronizer(AQS)框架,可以利用现代处理器的特性(如CAS操作)来优化锁的性能

二、ReentrantLock和Synchronized的区别

通过ReentrantLock 上述的特性,就可以了解与synchronized区别了

最好是理解记忆,切记死记硬背!

1、语法和使用方式

  • synchronized:关键字,可直接作用于方法或代码块,不需要显式地调用获取和释放锁的方法
  • ReentrantLock:类,需要通过 lock() 和 unlock() 明确地获取和释放锁。

2、锁的获取和释放

  • synchronized:自动释放锁,当线程退出作用域或发生异常时,锁会被自动释放
  • ReentrantLock:需要显式释放锁,如果在 unlock() 方法之前发生异常,锁可能不会被释放,需要使用 try-finally 块或 try-with-resources 语句来确保锁被释放。

3、高级特性

  • ReentrantLock:提供了更多的高级特性,如公平锁、非公平锁、超时等待、可中断等待等。
  • synchronized:只支持非公平锁,不支持超时等待或可中断等待

4、条件变量

  • synchronized中可以使用wait(),notify(),notifyAll()进行线程间的
  • ReentrantLock配合Condition对象提供了强大的线程间协调能力,可以有多个Condition,每个Condition管理自己的等待集

5、性能

  • synchronized:基于 JVM 实现,使用了多种锁优化技术,如偏向锁、轻量级锁和重量级锁。这些技术使得 synchronized 在许多情况下性能接近或优于 ReentrantLock
  • ReentrantLock:基于 JDK 实现,使用了 CAS(Compare and Swap)原子操作进行锁的获取和释放。ReentrantLock 提供了更多高级功能,如公平锁、非公平锁、可中断的锁等待等。

总结

  • synchronized:适用于大多数基本的同步需求,提供了简洁的语法,自动释放锁,适合于简单的同步场景。
  • ReentrantLock:适用于需要更高级特性的场景,如公平锁、超时等待等,需要显式管理锁的获取和释放。
  • 如果竞争比较激烈,推荐ReentrantLock去实现,不存在锁升级概念。而synchronized是存在锁升级概念的,如果升级到重量级锁,是不存在锁降级的。

三、ReentrantLock使用场景

JDK 在并发包中, 使用 ReetrantLock 的地方有:

  1. CyclicBarrier

  2. DelayQueue

  3. LinkedBlockingDeque

  4. ThreadPoolExecutor

  5. ReentrantReadWriteLock

  6. StampedLock

1. 生产者消费者模式
应用场景:在消息队列或缓存系统中,生产者负责产生数据,消费者负责消费数据。为了确保数据的一致性和线程安全,可以使用 ReentrantLock

2. 文件上传下载系统
应用场景:在一个文件上传下载系统中,多个用户可能同时访问同一文件。为了保证文件的一致性和安全性,可以使用 ReentrantLock 来同步文件的读写操作

3. 线程池中的任务调度
应用场景:在线程池中,多个线程可能需要调度任务执行。使用 ReentrantLock 可以确保任务的正确调度和执行顺序。

4. 数据库连接池
应用场景:数据库连接池中需要管理多个数据库连接。使用 ReentrantLock 可以确保线程安全地获取和释放数据库连接

5. 限流器
应用场景:在高并发系统中,为了防止服务器过载,可以使用限流器来限制请求的速率。使用 ReentrantLock 可以确保限流逻辑的线程安全性
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1988639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

量化方法介绍

一、定义 分类模型量化接口进阶量化支持的模式/流/硬件 二、实现 分类 模型量化接口进阶 https://pytorch.org/docs/stable/quantization-support.html 2.1 算子融合 定义&#xff1a; 将多个算子融合到一起&#xff0c;运算时可以加快运行速度。 import torch # define a…

三星和Nvidia在HBM3E芯片领域的竞争与合作

引言 近期&#xff0c;全球半导体市场的焦点逐渐聚焦在了高带宽内存&#xff08;HBM&#xff09;芯片领域&#xff0c;尤其是三星电子和Nvidia之间的竞争与合作。这两家科技巨头正在为下一代人工智能&#xff08;AI&#xff09;处理器的高性能需求而竞相研发先进的HBM3E存储解决…

模拟面试题1

目录 一、JVM的内存结构&#xff1f; 二、类加载器分为哪几类&#xff1f; 三、讲一下双亲委派机制 为什么要有双亲委派机制&#xff1f; 那你知道有违反双亲委派的例子吗&#xff1f; 四、IO 有哪些类型&#xff1f; 五、Spring Boot启动机制 六、Spring Boot的可执行…

基于MindFormers实现GPT2模型的推理

前言 针对MindFormers的安装&#xff0c;可参考本专栏里的另一篇博客 安装MindFormers&#xff08;昇腾910&#xff09;-CSDN博客 pipeline方式 from mindformers import pipeline from mindformers import GPT2LMHeadModel, GPT2Config, GPT2Tokenizer tok GPT2Tokenizer…

Kafka安装部署+go整合

1、Kafka的安装 1、下载与安装Kafka Kafka官网https://Kafka.apache.org/downloads 所以这里推荐的版本是 : https://archive.apache.org/dist/kafka/2.7.2/kafka_2.12-2.7.2.tgz 将下载下来的安装包直接解压到一个路径下即可完成Kafka的安装&#xff0c;这里统一将Kafka安装…

4种防止模态框弹出时页面滚动的方法

1. Overflow:hidden — 经典方法 overflow:hidden CSS 属性是一种久经考验的防止滚动的方法。只需将一个类&#xff08;例如&#xff0c;no-scroll&#xff09;添加到 <body> 标签&#xff0c;并将其链接到带有 overflow:hidden 的 CSS 规则。 .no-scroll {overflow: h…

地表最强?免费!AI画图模型:Stable Diffusion 3 来了!

前言 Stability AI终于推出了备受期待的Stable Diffusion 3 API。经过几个月技术报告的酝酿&#xff0c;现在用户终于可以实际体验这个模型啦。 虽然完全开源的SD3模型仍在开发中&#xff0c;Stability AI已承诺对普通用户免费开放。用户现在可以通过Fireworks AI平台访问SD3 …

电脑出现错误vcomp140.dll是什么情况?vcomp140.dll丢失怎样修复?

很多小伙伴在使用电脑时会突然收到提示vcomp140.dll文件丢失导致应用程序无法打开&#xff0c;不能正常运行。这是怎么一回事呢&#xff1f;其实就是vcomp140.dll文件被破会坏导致文件被丢失。具体的解决办法其实很简单一起来看看吧。 关于vcomp140.dll文件丢失的详细分析 在计…

我在高职教STM32——EXTI之外部按键中断(2)

大家好,我是老耿,高职青椒一枚,一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次,同行应该都懂的,老师在课堂上教学几乎是没什么成就感的。正是如此,才有了借助CSDN平台寻求认同感和成就感的想法。在这里,我准备陆续把自己花了很多心思设计的教学课件分…

小顶堆实现查找前 K 个高频元素

小顶堆&#xff08;Min-Heap&#xff09;通常用于实现优先队列。在小顶堆中&#xff0c;根节点的值是最小的&#xff0c;因此通过从堆中移除根节点&#xff0c;你可以高效地获取当前优先级最高&#xff08;即值最小&#xff09;的元素。 优先队列的特点&#xff1a; 允许高效…

2024年【化工自动化控制仪表】考试及化工自动化控制仪表考试内容

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 化工自动化控制仪表考试参考答案及化工自动化控制仪表考试试题解析是安全生产模拟考试一点通题库老师及化工自动化控制仪表操作证已考过的学员汇总&#xff0c;相对有效帮助化工自动化控制仪表考试内容学员顺利通过考…

Struts2框架漏洞(附漏洞修复方法)

Apache Struts 2 最初被称为 WebWork 2&#xff0c;它是一个简洁的、可扩展的框架&#xff0c;可用于创建企业级Java web应用程序。设计这个框架是为了从构建、部署、到应用程序维护方面来简化整个开发周期。 Struts 2在2007年7月23日发布的第一个Struts 2漏洞S2-001。 …

dbeaver设置字体大小

1、【窗口】-【首选项】 2、【外观】-【颜色-字体】-【Dbeaver Fonts】-【Monospace font】 双击或者右边编辑都可以打开设置

【Linux】—— 僵尸进程、孤儿进程

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;Linux跬步积累 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日一题 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0…

计网学习(一)——计算机网络概述

一、计算机网络概述 Internet翻译&#xff1a;因特网&#xff08;未得到普及&#xff09;>互联网互联网基本特点&#xff1a;连通性和资源共享计算机网络&#xff1a;有若干结点和连接这些节点的链路组成网络把许多计算机连接在一起&#xff0c;而互连网则把许多网络通过路…

数学建模--智能算法之免疫算法

目录 基本原理 应用实例 代码示例 总结 免疫算法在免疫系统研究中的应用和进展是什么&#xff1f; 如何量化评估免疫算法在不同优化问题中的性能和效率&#xff1f; 免疫算法与其他智能优化算法&#xff08;如遗传算法、粒子群优化&#xff09;相比有哪些独特优势和局限性…

“tcp控制协议”的理解

情景解释&#xff1a; 1.过程&#xff1a; 在用户进行网络间通信时&#xff0c;不管是客户端还是服务端&#xff0c;都会有两个缓冲区——发送缓冲区和接受缓冲区。 通过4个缓冲区进行数据交流。 用户通过write()将数据发送到他的发送缓冲区中&#xff0c;再传输到服务端的…

遥感类SCI推荐合集,潜力大+易投,版面有限!

关注GZH【欧亚科睿学术】&#xff0c;第一时间了解期刊最新动态&#xff01; &#x1f525; &#x1f525; &#x1f525; &#x1f525; 遥感类SCI期刊合集 1. 农林科学类&#xff08;中科院1区TOP&#xff0c;领域高权威&#xff09; 【期刊简介】IF&#xff1a;4.0-5.0&am…

Linux源码阅读笔记18-插入模型及删除模块操作

基础知识 模块是一种向Linux内核添加设备驱动程序、文件系统及其他组件的有效方法&#xff0c;不需要编译新内核 优点 通过使用模块&#xff0c;内核发布者能够预先编译大量驱动程序&#xff0c;而不会致使内核映像的尺寸发生膨胀。内核开发者可以将实验性的代码打包到模块中&a…

达梦数据库的系统视图v$large_mem_sqls

达梦数据库的系统视图v$large_mem_sqls 达梦数据库的V$LARGE_MEM_SQLS视图提供了最近1000条使用大内存的SQL语句信息。一条SQL语句如果使用的内存值超过ini参数LARGE_MEM_THRESHOLD&#xff0c;就认为使用了大内存。这个视图帮助用户监控和分析哪些SQL语句在执行时占用了大量内…