详解Java并发之Condition

详解Java并发之Condition

Condition是什么?

Condition是Java并发包中的一个接口,它是对传统Object.wait()和Object.notify()方法的增强,可以更灵活地实现线程的等待和通知。

创建一个Condition对象

创建Condition对象通常是在Lock对象的基础上创建的,可以通过Lock接口的newCondition()方法创建。例如下面的示例:

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

Condition的方法

Condition接口有三个常用的方法:

  1. await():等待,进入等待队列,释放当前线程获得的锁,直到被其它线程发出唤醒信号或被中断。
  2. signal():唤醒一个等待在Condition上的线程,如果有多个线程在等待,则随机选择一个。
  3. signalAll():唤醒所有等待在Condition上的线程。

Condition的基本使用

下面是一个基本的Condition使用示例,该程序启动了两个线程,线程A打印0~4,线程B打印A~E,两个线程交替执行。可以看到,线程的等待和唤醒是通过Condition对象来实现的。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionDemo {
    private int state = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        final ConditionDemo demo = new ConditionDemo();
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                demo.printNumbers();
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                demo.printLetters();
            }
        });
        threadA.start();
        threadB.start();
        threadA.join();
        threadB.join();
    }

    private void printNumbers() {
        lock.lock();
        try {
            for (int i = 0; i < 5; i++) {
                while (state % 2 == 1) {
                    condition.await();
                }
                System.out.print(i);
                state++;
                condition.signal();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    private void printLetters() {
        lock.lock();
        try {
            for (char c = 'A'; c <= 'E'; c++) {
                while (state % 2 == 0) {
                    condition.await();
                }
                System.out.print(c);
                state++;
                condition.signal();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

Condition的应用实例

下面再来看一下Condition的一个应用实例,实现一个有界队列。这个队列有两个方法:put()方法往队列中放入数据,如果队列已满则等待;take()方法从队列中取出数据,如果队列为空则等待。

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BoundedQueue<T> {
    private Queue<T> queue;
    private int maxSize;
    private Lock lock = new ReentrantLock();
    private Condition notEmpty = lock.newCondition();
    private Condition notFull = lock.newCondition();

    public BoundedQueue(int maxSize) {
        this.maxSize = maxSize;
        queue = new LinkedList<T>();
    }

    public void put(T element) throws InterruptedException {
        lock.lock();
        try {
            while (queue.size() == maxSize) {
                notFull.await();
            }
            queue.offer(element);
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public T take() throws InterruptedException {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                notEmpty.await();
            }
            T element = queue.poll();
            notFull.signal();
            return element;
        } finally {
            lock.unlock();
        }
    }
}

可以测试一下这个有界队列的效果:

public class BoundedQueueDemo {
    public static void main(String[] args) {
        final BoundedQueue<Integer> queue = new BoundedQueue<Integer>(5);
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("Put: " + i);
                    try {
                        queue.put(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        System.out.println("Take: " + queue.take());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        threadA.start();
        threadB.start();
    }
}

这个程序会启动两个线程,线程A从0开始往队列中放入10个整数,线程B每隔1秒钟从队列中取出一个整数并打印出来。可以看到,由于队列有界,当队列满了时,线程A会等待线程B来取走数据,反之亦然。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Java并发之Condition - Python技术站

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

相关文章

  • 使用redis分布式锁解决并发线程资源共享问题

    使用Redis分布式锁是一种解决资源共享问题的常用方式。下面是使用Redis分布式锁解决并发线程资源共享问题的完整攻略。 1. 引入Redis依赖 Redis是内存数据库,我们需要引入redis的Java客户端依赖。一般有两个比较常用的Java客户端依赖jar包:Jedis和Lettuce。这里以Jedis为例。 <dependency> &lt…

    多线程 2023年5月16日
    00
  • 易语言启用多线程方法实例分享

    易语言启用多线程方法实例分享 多线程编程是一种常见的编程模式,易语言作为一种可视化编程语言,支持使用多线程方式来实现异步处理,提高程序的性能和响应速度。本文将分享易语言启用多线程的实现方法和示例,帮助读者了解多线程编程的基本原理和使用方法。 多线程编程基本原理 在多线程编程中,程序将同时执行多个线程,每个线程独立执行不同的任务。线程的执行顺序和时间不确定,程…

    多线程 2023年5月17日
    00
  • Java多线程run方法中直接调用service业务类应注意的问题及解决

    下面是关于“Java多线程run方法中直接调用service业务类应注意的问题及解决”的完整攻略: 问题描述 在Java的多线程程序中,run方法中直接调用service业务类可能会带来以下问题: 业务逻辑的复杂度增加,使得程序难以维护和扩展; 可能会导致死锁或同步问题,因为run方法本身就是在一个线程中执行的,如果在其中调用service方法,可能会导致与…

    多线程 2023年5月16日
    00
  • 反对使用Spring封装的多线程类原因

    请你注意阅读以下几个方面的攻略: 1. 为什么不建议使用Spring封装的多线程类 在Spring中封装了ThreadPoolTaskExecutor、Async和Schedulers等多线程实现类,使得我们可以很方便地进行线程操作。但是,使用Spring封装的多线程类存在以下问题: 代码的耦合性增加:线程池、线程数量等都是封装无法自定义配置,会使类与Spr…

    多线程 2023年5月16日
    00
  • Java并发编程(CyclicBarrier)实例详解

    Java并发编程(CyclicBarrier)实例详解 概述 Java并发编程的一个重要组成部分就是同步化,也就是为了解决多线程情况下线程之间的通信和数据共享的问题。在实际开发中,有些业务场景需要多个线程一起协作完成某个任务,这个时候就需要用到CyclicBarrier。 CyclicBarrier是一个同步工具类,当线程执行到CyclicBarrier的时…

    多线程 2023年5月16日
    00
  • java多线程实现文件下载

    实现文件下载的过程中,可以通过使用多线程技术来提高文件下载速度。在Java中,可以利用Java多线程机制实现文件下载。下面是一个具体的实现攻略。 1. 多线程下载原理 多线程下载的原理是将一个大文件划分为若干个较小的文件块,每个线程分别下载不同的文件块。通过多个线程同时下载不同的文件块,可以加快整个文件的下载速度。同时,在下载过程中还需要考虑线程的安全性问题…

    多线程 2023年5月16日
    00
  • 详解java解决分布式环境中高并发环境下数据插入重复问题

    详解 Java 解决分布式环境中高并发环境下数据插入重复问题 背景 在高并发环境下,数据插入操作很容易出现重复插入的问题。例如,多个用户同时提交一个相同的表单,系统可能会将同样的数据插入数据库中多次,造成数据不一致的问题。这种情况在分布式环境下尤其常见,因为不同节点的时间戳可能不一致。 解决方案 方法一:利用 Unique 约束 在数据库中设置 Unique…

    多线程 2023年5月16日
    00
  • 从并发到并行解析Go语言中的sync.WaitGroup

    从并发到并行解析Go语言中的sync.WaitGroup是一篇介绍Go语言中并发编程工具的文章。在该篇文章中,我们会深入了解到什么是并发和并行,以及如何使用sync.WaitGroup来协调并发和并行工作。 并发和并行的定义 并发是指同时执行多个代码段,但并不保证这些代码段的执行顺序。一个被操作系统调度器管理的Go程序就是一个并发程序。 并行是指同时执行多个…

    多线程 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部