Java多线程Condition接口原理介绍

下面是对于Java多线程Condition接口的原理介绍:

Condition接口是什么?

在Java中,我们可以使用synchronizedwait()notify()notifyAll()等来进行线程同步和通信。而条件对象(Condition)是在Java 5中新增的,它可以更加灵活地控制线程的等待和唤醒,提供了更高级、更安全、更灵活的线程同步方式。

Condition的基本使用

条件对象是与一个锁绑定的,要创建一个条件对象,我们需要先获取锁,然后使用ReentrantLock类的方法newCondition()来创建:

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

这样我们就创建了一个条件变量,下一步就可以通过调用conditionawait()方法使得线程进入等待状态,直到调用conditionsignalAll()方法或者signal()方法唤醒线程。

下面是一个简单的示例,两个线程分别执行加和减操作,当结果为零时,主线程输出结果并结束程序。具体的实现过程如下:

public class ConditionDemo {
    private int sum;

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

    public void add() {
        lock.lock();
        try {
            sum++;
            System.out.println(Thread.currentThread().getName() + " add: " + sum);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void sub() {
        lock.lock();
        try {
            while (sum == 0) {
                condition.await();
            }
            sum--;
            System.out.println(Thread.currentThread().getName() + " sub: " + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

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

        Runnable addTask = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    demo.add();
                }
            }
        };

        Runnable subTask = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    demo.sub();
                }
            }
        };

        Thread addThread1 = new Thread(addTask);
        Thread addThread2 = new Thread(addTask);
        Thread subThread = new Thread(subTask);

        addThread1.start();
        addThread2.start();
        subThread.start();

        try {
            addThread1.join();  // 等待线程结束
            addThread2.join();
            subThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Result: " + demo.sum);
    }
}

上述程序中,使用了一个变量sum来保存加减的结果。在加操作中,我们先获取锁,然后将sum增加1,输出结果,并唤醒所有等待condition的线程。在减操作中,我们先获取锁,然后不断判断sum是否为0,如果为0,则调用conditionawait()方法等待;直到被唤醒后,将sum减1,并输出结果。在主线程中,我们启动两个加操作线程和一个减操作线程,等待所有线程运行结束后,输出结果。

使用Condition实现生产者-消费者模式

生产者-消费者模式是大家比较熟悉的一种应用场景。可以使用Condition来实现,示例如下:

public class ProducerConsumerDemo {

    private LinkedList<Integer> buffer = new LinkedList<Integer>();

    private ReentrantLock lock = new ReentrantLock();
    private Condition notEmpty = lock.newCondition();
    private Condition notFull = lock.newCondition();

    public void produce() {
        lock.lock();
        try {
            while (buffer.size() == 10) {
                notFull.await();
            }
            int value = new Random().nextInt(100);
            buffer.addLast(value);
            System.out.println(Thread.currentThread().getName() + " produce " + value);
            notEmpty.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public int consume() {
        lock.lock();
        try {
            while (buffer.size() == 0) {
                notEmpty.await();
            }
            int value = buffer.removeFirst();
            System.out.println(Thread.currentThread().getName() + " consume " + value);
            notFull.signalAll();
            return value;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return -1;
        } finally {
            lock.unlock();
        }
    }

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

        Runnable produceTask = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    demo.produce();
                }
            }
        };

        Runnable consumeTask = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    demo.consume();
                }
            }
        };

        Thread producer1 = new Thread(produceTask, "producer1");
        Thread producer2 = new Thread(produceTask, "producer2");
        Thread consumer1 = new Thread(consumeTask, "consumer1");
        Thread consumer2 = new Thread(consumeTask, "consumer2");

        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();

        try {
            producer1.join();
            producer2.join();
            consumer1.join();
            consumer2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在上述示例中,我们使用了一个LinkedList来存储数据。在生产操作中,如果buffer已经满了,那就调用notFull.await()等待;直到有消费者调用了consume()方法,拿走了一些数据,此时有足够的空间存储新的数据,就可以唤醒正在等待的生产者线程。在消费操作中,如果buffer为空,就调用notEmpty.await()等待;直到有生产者调用了produce()方法,放入了一些数据,此时就可以从buffer中取出数据,唤醒正在等待的消费者线程。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程Condition接口原理介绍 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Java倒计时三种实现方式代码实例

    首先我们需要了解倒计时的基本概念和工作原理。倒计时是指从一个特定的时间开始向下计数,直到达到预定目标时间。在计数过程中需要实时更新显示时间。Java提供了多种实现方式,下面将分别进行介绍。 基于Thread类实现倒计时 实现步骤 继承Thread类,重写run()方法,在该方法中实现倒计时的逻辑。 在run()方法中使用Thread.sleep()方法控制倒…

    Java 2023年5月18日
    00
  • Java的Struts框架报错“InvalidRoleException”的原因与解决办法

    当使用Java的Struts框架时,可能会遇到“InvalidRoleException”错误。这个错误通常由以下原因之一起: 配置错误:如果配置文件中没有正确配置角色,则可能会出现此。在这种情况下,需要检查配置文件以解决此问题。 角色名称错误:如果角色名称不正确,则可能会出现此。在这种情况下,需要检查角色名称以解决此问题。 以下是两个实例: 例 1 如果配…

    Java 2023年5月5日
    00
  • Spring和SpringMVC扫描注解类冲突的解决方案

    在Spring和SpringMVC中,都有扫描注解类的功能。但是,如果在两个框架中同时使用了相同的注解类,就会出现冲突。本文将详细讲解Spring和SpringMVC扫描注解类冲突的解决方案,并提供两个示例说明。 解决方案一:使用不同的包名 我们可以在Spring和SpringMVC中使用不同的包名,来避免扫描相同的注解类。下面是一个示例: // Sprin…

    Java 2023年5月18日
    00
  • Redis Plus 来了,性能炸裂!

    来源:https://developer.aliyun.com/article/705239 1 什么是KeyDB? KeyDB是Redis的高性能分支,专注于多线程,内存效率和高吞吐量。除了多线程之外,KeyDB还具有仅在Redis Enterprise中可用的功能,例如Active Replication,FLASH存储支持以及一些根本不可用的功能,例如…

    Java 2023年4月25日
    00
  • JavaEE SpringMyBatis是什么? 它和Hibernate的区别及如何配置MyBatis

    JavaEE SpringMyBatis是JavaEE开发的一种技术栈组合,主要包含Spring框架和MyBatis持久层框架,用于简化JavaEE应用程序的开发和管理。下面分别详细讲解JavaEE、Spring和MyBatis以及它们之间的区别,最后提供MyBatis的配置攻略和示例。 JavaEE是什么? JavaEE(Java Enterprise E…

    Java 2023年5月19日
    00
  • Java StringBuilder的用法示例

    接下来我将为你详细讲解Java StringBuilder的用法示例。 什么是StringBuilder 在Java中,如果需要大量修改字符串时,使用字符串拼接是不太合适的方式,会带来一定的性能问题。因此,Java提供了StringBuilder类,它是一个可变的字符串序列。相比于String类,它能够更加高效地进行字符串的操作。 StringBuilder…

    Java 2023年5月27日
    00
  • 浅谈spring security入门

    浅谈Spring Security入门 简介 Spring Security是Spring框架的安全性解决方案之一。它为Spring应用程序提供了身份验证、授权和其他安全功能。Spring Security是一种基于过滤器的安全性实现,可通过在Web应用程序中添加一组过滤器来提供许多基本的安全性机制,如基本认证、表单认证、单点登录等。 安装 在maven项目…

    Java 2023年5月20日
    00
  • 什么是类加载器的双亲委派模型的实现原理?

    类加载器的双亲委派模型是Java虚拟机用于加载类的一种规范,它保证在Java中每个类都有且仅有一个类对象,从而保证Java程序的正确性和安全性。本文将详细讲解类加载器双亲委派模型的实现原理。 双亲委派模型的概述 在Java虚拟机中,每个类都有一个唯一的全限定名,类加载器加载一个类时需要先检查父加载器是否已经加载该类。如果父加载器没有加载该类,则它会使用自己的…

    Java 2023年5月10日
    00
合作推广
合作推广
分享本页
返回顶部