java——PV操作

PV操作通常指的是P操作和V操作,它们是信号量(Semaphore)机制中的两个基本操作,用于解决进程或线程间的同步和互斥问题。P操作(也称为wait操作或down操作)用于将信号量的值减1,如果结果为负数,则调用该操作的进程或线程会被阻塞;V操作(也称为signal操作或up操作)用于将信号量的值加1,如果有任何进程或线程因为P操作而被阻塞,则唤醒其中一个。

在Java中,我们可以使用java.util.concurrent包中的Semaphore类来实现PV操作。以下是一个简单的示例:

java 复制代码
import java.util.concurrent.Semaphore;

public class PVExample {
    // 创建一个Semaphore对象,初始值为1(表示只有一个资源)
    private static Semaphore semaphore = new Semaphore(1);

    public static void main(String[] args) {
        Thread producer = new Thread(new Producer());
        Thread consumer = new Thread(new Consumer());

        producer.start();
        consumer.start();
    }

    // 生产者线程
    static class Producer implements Runnable {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println("Producer is producing item " + i);
                    // 模拟生产一个物品的过程
                    Thread.sleep(1000);

                    // P操作:请求资源(信号量减1)
                    semaphore.acquire();

                    // 这里可以放置生产物品后的处理逻辑

                    System.out.println("Producer has produced item " + i + " and released the resource.");

                    // 模拟生产完成后释放资源的过程(为了演示,这里直接释放)
                    // 实际上,应该在消费者消费完资源后再释放
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // 消费者线程
    static class Consumer implements Runnable {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 5; i++) {
                    // V操作:释放资源(信号量加1)
                    // 注意:这里的V操作应该放在消费资源之后,但为了演示,我们先进行V操作
                    semaphore.release();

                    // 等待获取资源(即P操作),然后消费资源
                    semaphore.acquire();

                    System.out.println("Consumer is consuming item " + i);

                    // 模拟消费一个物品的过程
                    Thread.sleep(1500);

                    System.out.println("Consumer has consumed item " + i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

注意 :上述代码只是一个演示,实际使用中,P操作(semaphore.acquire())应该在消费或处理资源之前进行,V操作(semaphore.release())应该在消费或处理资源之后进行。同时,上述代码中的生产和消费逻辑并不严谨,因为semaphore.release()在acquire()之前调用会导致信号量的值错误地增加。

正确的逻辑应该是:

  1. 生产者生产一个物品后,调用semaphore.acquire()请求资源(P操作)。
  2. 如果资源可用(信号量大于0),则生产者继续执行,并将信号量减1。
  3. 如果资源不可用(信号量等于0),则生产者被阻塞,直到消费者释放资源。
  4. 消费者消费一个物品后,调用semaphore.release()释放资源(V操作),将信号量加1。
  5. 如果有被阻塞的生产者或消费者,则唤醒其中一个。

在实际应用中,你需要根据具体场景调整上述逻辑。

相关推荐
驭渊的小故事17 分钟前
Spring AOP 核心概念与通知类型详解
java·后端·spring
vipxieliang18 分钟前
ValidX vs 手写验证代码:开发效率对比实测
java·spring boot·后端
白杨尚青35 分钟前
C++进阶篇(五):红黑树——四条规则、三种插入情况与旋转变色
开发语言·数据结构·c++·stl·红黑树·平衡二叉树
vipxieliang38 分钟前
虚拟线程与 GraalVM:Spring Boot 3.x 云原生性能跃迁
java·spring boot·后端
Rain的Java大神之路38 分钟前
面试官最烦的答案:“我用 Redis + Token”!接口幂等 8 种方案 + 四层防御,把重复扣款工单干到 0
java·后端·面试
.道阻且长.42 分钟前
Linux基本开发工具:gdb和cgdb的使用
linux·运维·服务器·开发语言
Rainmicro1 小时前
【无标题】
java·数据库·算法
starzy19901 小时前
深入理解Scala匿名函数:函数式编程基石
开发语言·scala
驭渊的小故事1 小时前
Spring AOP 入门:从 AOP 概念到第一个耗时统计切面
java·后端·spring
天天被压力2 小时前
【A股分钟级高频数据完全手册 #09】A股历史分时交易数据接口:普通分时怎么批量下
java·人工智能·python