返回顶部
首页 > 资讯 > 精选 >java并发等待条件的示例分析
  • 859
分享到

java并发等待条件的示例分析

java 2023-05-30 22:05:53 859人浏览 薄情痞子
摘要

这篇文章将为大家详细讲解有关java并发等待条件的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。前言前面介绍了排它锁,共享锁的实现机制,本篇继续学习AQS中的另外一个内容-Condition。想必

这篇文章将为大家详细讲解有关java并发等待条件的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

前言

前面介绍了排它,共享锁的实现机制,本篇继续学习AQS中的另外一个内容-Condition。想必学过java的都知道Object.wait和Object.notify,同时也应该知晓这两个方法的使用离不开synchronized关键字。synchronized是JVM级别提供的同步原语,它的实现机制隐藏在jvm实现中。作为Lock系列功能中的Condition,就是用来实现类似 Object.wait和Object.notify 对应功能的。

使用场景

为了更好的理解Lock和Condition的使用场景,下面我们先来实现这样一个功能:有多个生产者,多个消费者,一个产品容器,我们假设容器最多可以放3个产品,如果满了,生产者需要等待产品被消费,如果没有产品了,消费者需要等待。我们的目标是一共生产10个产品,最终消费10个产品,如何在多线程环境下完成这一挑战呢?下面是我简单实现的一个demo,仅供参考。

package com.lock.condition.test;import java.util.LinkedList;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicInteger;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class LockConditionTest {  // 生产 和 消费 的最大总数  public static int totalCount = 10;  // 已经生产的产品数  public static volatile int hasProduceCount = 0;  // 已经消费的产品数  public static volatile int hasConsumeCount = 0;  // 容器最大容量  public static int containerSize = 3;  // 使用公平策略的可重入锁,便于观察演示结果  public static ReentrantLock lock = new ReentrantLock(true);  public static Condition notEmpty = lock.newCondition();  public static Condition notFull = lock.newCondition();  // 容器  public static LinkedList<integer> container = new LinkedList<integer>();  // 用于标识产品  public static AtomicInteger idGenerator = new AtomicInteger();  public static void main(String[] args) {    Thread p1 = new Thread(new Producer(), "p-1");    Thread p2 = new Thread(new Producer(), "p-2");    Thread p3 = new Thread(new Producer(), "p-3");    Thread c1 = new Thread(new Consumer(), "c-1");    Thread c2 = new Thread(new Consumer(), "c-2");    Thread c3 = new Thread(new Consumer(), "c-3");    c1.start();    c2.start();    c3.start();    p1.start();    p2.start();    p3.start();    try{      c1.join();      c2.join();      c3.join();      p1.join();      p2.join();      p3.join();    }catch(Exception e){    }    System.out.println(" done. ");  }  static class Producer implements Runnable{    @Override    public void run() {      while(true){        lock.lock();        try{          // 容器满了,需要等待非满条件          while(container.size() >= containerSize){            notFull.await();          }          // 到这里表明容器未满,但需要再次判断是否已经完成了任务          if(hasProduceCount >= totalCount){            System.out.println(Thread.currentThread().getName()+" producer exit");            return ;          }          int product = idGenerator.incrementAndGet();          // 把生产出来的产品放入容器          container.addLast(product);          System.out.println(Thread.currentThread().getName() + " product " + product);          hasProduceCount++;          // 通知消费线程可以去消费了          notEmpty.signal();        } catch (InterruptedException e) {        }finally{          lock.unlock();        }      }    }  }  static class Consumer implements Runnable{    @Override    public void run() {      while(true){        lock.lock();        try{          if(hasConsumeCount >= totalCount){            System.out.println(Thread.currentThread().getName()+" consumer exit");            return ;          }          // 一直等待有产品了,再继续往下消费          while(container.isEmpty()){            notEmpty.await(2, TimeUnit.SECONDS);            if(hasConsumeCount >= totalCount){              System.out.println(Thread.currentThread().getName()+" consumer exit");              return ;            }          }          Integer product = container.removeFirst();          System.out.println(Thread.currentThread().getName() + " consume " + product);          hasConsumeCount++;          // 通知生产线程可以继续生产产品了          notFull.signal();        } catch (InterruptedException e) {        }finally{          lock.unlock();        }      }    }  }}

一次执行结果如下:

p-1 product 1p-3 product 2p-2 product 3c-3 consume 1c-2 consume 2c-1 consume 3p-1 product 4p-3 product 5p-2 product 6c-3 consume 4c-2 consume 5c-1 consume 6p-1 product 7p-3 product 8p-2 product 9c-3 consume 7c-2 consume 8c-1 consume 9p-1 product 10p-3 producer exitp-2 producer exitc-3 consume 10c-2 consumer exitc-1 consumer exitp-1 producer exitc-3 consumer exit done.

从结果可以发现已经达到我们的目的了。

深入理解Condition的实现原理

上面的示例只是为了展示 Lock结合Condition可以实现的一种经典场景,在有了感性的认识之后,我们将一步一步来观察Lock和Condition是如何协作完成这一任务的,这也是本篇的核心内容。

为了更好的理解和演示这一个过程,我们使用到的锁是使用公平策略模式的,我们会使用上面例子运作的流程。我们会使用到3个生产线程,3个消费线程,分别表示 p1、p2、p3和c1、c2、c3。

Condition的内部实现是使用节点链来实现的,每个条件实例对应一个节点链,我们有notEmpty 和 notFull 两个条件实例,所以会有两个等待节点链。

一切准备就绪 ,开始我们的探索之旅。

线程c3执行,然后发现没有产品可以消费,执行 notEmpty.await,进入等待队列中等候。

java并发等待条件的示例分析

线程c2和线程c1执行,然后发现没有产品可以消费,执行 notEmpty.await,进入等待队列中等候。

java并发等待条件的示例分析

线程 p1 启动,得到了锁,p1开始生产产品,这时候p3抢在p2之前,执行了lock操作,结果p2和p3都处于等待状态,入同步队列等待。<喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="这里写图片描述" src="/uploadfile/Collfiles/20160912/20160912092710536.png" title="\" />

注意,本例中我们使用的是公平策略模式下的排它锁,由于p3抢先执行取锁操作,所以虽然p2和p3都被阻塞了,但是p3会优先被唤醒 。

这会,p1生产完毕,通知 not empty等待队列,可以唤醒一个等待线程节点了,然后释放了锁,释放锁会导致p3被唤醒,然后p1进入下一个循环,进入同步队列。

java并发等待条件的示例分析

事情开始变得有趣了,p1执行一次生产后,执行了 notEmpty.signal,其效果就是把 not empty等待列表中的头节点,即c3节点移到同步等待列队中,重新参与抢占锁。

p3生产完了产品后,继续notEmpty.signal,同时释放锁,释放锁后会唤醒p2线程,然后p3在下一轮尝试获取锁的时候,再次入队。

java并发等待条件的示例分析

接着,p2继续生产,生产后执行 notEmpty.signal,同时释放锁,释放锁后唤醒c3线程,然后p2在下一轮尝试取锁的时候,入列。

java并发等待条件的示例分析

c3进行消费,你可以看到,现在 not empty等待列队中已经没有等待节点了,由于我们使用的是公平策略排它锁,这就会导致同步队列中的节点一个接着一个执行,而目前同步队列中的节点排列为一生产,一消费,这不难可以知道,接下来代码已经不会进入 wait条件了,所以一个一个轮流执行就是,比如c3,执行完了,继续notFull.signal(); 然后释放锁,入队,这里要明白,notFull.signal();这句代码其实没有作用了,因为 not full等待队列中没有任何等待线程节点。 c3执行后,状态如下图所示:

java并发等待条件的示例分析

关于“java并发等待条件的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

--结束END--

本文标题: java并发等待条件的示例分析

本文链接: https://www.lsjlt.com/news/221691.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • java并发等待条件的示例分析
    这篇文章将为大家详细讲解有关java并发等待条件的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。前言前面介绍了排它锁,共享锁的实现机制,本篇继续学习AQS中的另外一个内容-Condition。想必...
    99+
    2023-05-30
    java
  • js中等待Promises的示例分析
    这篇文章给大家分享的是有关js中等待Promises的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。等待 Promises在某些情况下,我们需要等待多个Promise结束,这里,我们使用Promise.a...
    99+
    2023-06-27
  • JavaScript等待文件实例分析
    这篇文章主要介绍了JavaScript等待文件实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JavaScript等待文件实例分析文章都会有所收获,下面我们一起来看看吧。...
    99+
    2024-04-02
  • jQuery中EasyUI页面加载等待及页面等待层的示例分析
    这篇文章主要为大家展示了“jQuery中EasyUI页面加载等待及页面等待层的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“jQuery中EasyUI页...
    99+
    2024-04-02
  • java高并发中并发级别的示例分析
    这篇文章给大家分享的是有关java高并发中并发级别的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。阻塞一个线程是阻塞的,那么在其他线程释放资源之前,当前线程无法继续执行。当我们使用synchronized...
    99+
    2023-06-25
  • Java中并发容器的示例分析
    这篇文章给大家分享的是有关Java中并发容器的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、并发容器1.1 JDK 提供的并发容器总结JDK 提供的这些容器大部分在java.util.concurre...
    99+
    2023-06-15
  • Java父线程等待所有子线程退出的示例分析
    这篇文章主要介绍了Java父线程等待所有子线程退出的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。实例如下:static void testLoc...
    99+
    2023-05-30
    java
  • CentOS系统中跟踪高IO等待的示例分析
    这篇文章主要为大家展示了“CentOS系统中跟踪高IO等待的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“CentOS系统中跟踪高IO等待的示例分析”这篇文章吧。高IO等待问题的第一个征...
    99+
    2023-06-10
  • java并发中wait notify notifyAll的示例分析
    这篇文章主要介绍java并发中wait notify notifyAll的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、前言java 面试是否有被问到过,sleep 和 wait 方法的区别,关于这个问题...
    99+
    2023-06-15
  • Java并发中AQS原理的示例分析
    这篇文章给大家分享的是有关Java并发中AQS原理的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。线程阻塞原语Java 的线程阻塞和唤醒是通过 Unsafe 类的 park 和 unpark 方法做到的。...
    99+
    2023-06-02
  • oracle等待事件类型wait_class的分析
    oracle等待事件类型wait_class的分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。 Oracle 的...
    99+
    2024-04-02
  • JAVA并发中VOLATILE关键字的示例分析
    小编给大家分享一下JAVA并发中VOLATILE关键字的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!并发编程中的三个概念:1.原子性在Java中,对基本...
    99+
    2023-06-15
  • Java中多线程与并发的示例分析
    这篇文章主要介绍Java中多线程与并发的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、进程与线程进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。线程:是进程的一个执行路径,一个...
    99+
    2023-06-15
  • Java并发中守护线程的示例分析
    今天就跟大家聊聊有关Java并发中守护线程的示例分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在Java中有两类线程:用户线程 (User Thread)、守护线程 (Daemo...
    99+
    2023-06-17
  • 软件系统中高并发的示例分析
    这篇文章将为大家详细讲解有关软件系统中高并发的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。概述当前,数字化在给企业带来业务创新,推动企业高速发展的同时,也给企业的IT软件系统带来了严峻的挑战。面...
    99+
    2023-06-15
  • go:垃圾回收GC触发条件的示例分析
    这篇文章将为大家详细讲解有关go:垃圾回收GC触发条件的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。什么是gogo是golang的简称,golang 是Google开发的一种静态强类型、编译型、...
    99+
    2023-06-14
  • golang中并发和并行的示例分析
    这篇文章主要介绍了golang中并发和并行的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。什么是golanggolang 是Google开发的一种静态强类型、编译型、...
    99+
    2023-06-15
  • java中volatile变量并发操作的示例分析
    小编给大家分享一下java中volatile变量并发操作的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java的特点有哪些Java的特点有哪些1.Jav...
    99+
    2023-06-14
  • Java并发编程之ConcurrentLinkedQueue源码的示例分析
    这篇文章给大家分享的是有关Java并发编程之ConcurrentLinkedQueue源码的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、ConcurrentLinkedQueue介绍并编程中,一般需...
    99+
    2023-06-15
  • Java面试题之并发编程的示例分析
    小编给大家分享一下Java面试题之并发编程的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!面试题1:说一下你对ReentrantLock的理解?ReentrantLock是JDK1.5引入的,它拥有与synchro...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作