iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >如何使用JCTools实现Java并发程序
  • 327
分享到

如何使用JCTools实现Java并发程序

2024-04-02 19:04:59 327人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录概述非阻塞算法依赖JCTools队列队列实现原子队列容量其他数据结构工具性能测试使用JCTools的缺点结论概述 在本文中,我们将介绍JCTools(java并发工具)库。 简

概述

在本文中,我们将介绍JCTools(java并发工具)库。

简单地说,这提供了许多适用于多线程环境的实用数据结构。

非阻塞算法

传统上,在可变共享状态下工作的多线程代码使用来确保数据一致性和发布(一个线程所做的更改对另一个线程可见)。

这种方法有许多缺点:

  • 线程在试图获取锁时可能会被阻塞,在另一个线程的操作完成之前不会取得任何进展—这有效地防止了并行性
  • 锁争用越重,JVM处理调度线程、管理争用和等待线程队列的时间就越多,实际工作就越少
  • 如果涉及多个锁,并且它们以错误的顺序获取/释放,则可能出现死锁
  • 优先级反转的危险是可能的——高优先级线程被锁定,试图获得由低优先级线程持有的锁
  • 大多数情况下,使用粗粒度锁会严重损害并行性—细粒度锁需要更仔细的设计,增加锁开销,并且更容易出错

另一种方法是使用非阻塞算法,即任何线程的故障或挂起都不会导致另一个线程的故障或挂起的算法。

如果所涉及的线程中至少有一个能够在任意时间段内取得进展,即在处理过程中不会出现死锁,则非阻塞算法是无锁的。

此外,如果保证每个线程的进程,这些算法是无等待的。

下面是一个非阻塞堆栈示例,它定义了基本状态:


public class ConcurrentStack<E> {

  AtomicReference<node<E>> top = new AtomicReference<Node<E>>();

  private static class Node <E> {
    public E item;
    public Node<E> next;

    // standard constructor
  }
}

还有一些api方法:


public void push(E item){
  Node<E> newHead = new Node<E>(item);
  Node<E> oldHead;
  
  do {
    oldHead = top.get();
    newHead.next = oldHead;
  } while(!top.compareAndSet(oldHead, newHead));
}

public E pop() {
  Node<E> oldHead;
  Node<E> newHead;
  do {
    oldHead = top.get();
    if (oldHead == null) {
      return null;
    }
    newHead = oldHead.next;
  } while (!top.compareAndSet(oldHead, newHead));
  
  return oldHead.item;
}

我们可以看到,该算法使用细粒度比较和交换(CAS)指令,并且是无锁的(即使多个线程调用top.compareAndSet()同时,它们中的一个保证会成功)但不能无等待,因为不能保证CAS最终会对任何特定线程成功。

依赖

首先,让我们将JCTools依赖项添加到pom.xml文件:


<dependency>
  <groupId>org.jctools</groupId>
  <artifactId>jctools-core</artifactId>
  <version>2.1.2</version>
</dependency>

请注意,Maven Central上提供了最新的可用版本。

JCTools队列

该库提供了许多队列以在多线程环境中使用,即一个或多个线程以线程安全的无锁方式写入队列,一个或多个线程以线程安全的无锁方式从队列中读取。

所有队列实现的通用接口是org.jctools.queues.MessagePassingQueue。

队列类型
所有队列都可以根据其生产者/消费者策略进行分类:

  • 单个生产者,单个消费者–此类类使用前缀Spsc命名,例如SpscArrayQueue
  • 单个生产者,多个消费者–使用Spmc前缀,例如SpmcArrayQueue
  • 多个生产者,单个消费者-使用Mpsc前缀,例如MpscArrayQueue
  • 多个生产者、多个消费者—使用Mpmc前缀,例如MpmcArrayQueue

需要注意的是,在内部没有策略检查,也就是说,如果使用不正确,队列可能会无声地发生故障。

例如,下面的测试从两个线程填充单个生产者队列并通过,即使不能保证使用者看到来自不同生产者的数据:


SpscArrayQueue<Integer> queue = new SpscArrayQueue<>(2);

Thread producer1 = new Thread(() -> queue.offer(1));
producer1.start();
producer1.join();

Thread producer2 = new Thread(() -> queue.offer(2));
producer2.start();
producer2.join();

Set<Integer> froMQueue = new HashSet<>();
Thread consumer = new Thread(() -> queue.drain(fromQueue::add));
consumer.start();
consumer.join();

assertThat(fromQueue).containsOnly(1, 2);

队列实现

总结以上分类,以下是JCTools队列列表:

  • SpscArrayQueue–单个生产者,单个消费者,在内部使用一个数组,限制容量
  • SpscLinkedQueue–单个生产者,单个消费者,内部使用链表,未绑定容量
  • SpscChunkedArrayQueue–单生产商、单消费者,从初始容量开始,一直增长到最大容量
  • SpscGrowableArrayQueue–单生产者、单消费者,从初始容量开始,一直增长到最大容量。这与SpscChunkedArrayQueue是相同的契约,唯一的区别是内部块管理。建议使用SpscChunkedArrayQueue,因为它有一个简化的实现
  • SpscUnboundedArrayQueue–单个生产者,单个消费者,在内部使用数组,未绑定容量
  • SpmcArrayQueue–单个生产者、多个使用者,在内部使用一个阵列,限制容量
  • MpscArrayQueue—多个生产者、单个消费者在内部使用一个阵列,限制容量
  • MpscLinkedQueue–多个生产者,单个消费者,在内部使用链表,未绑定容量
  • MpmcArrayQueue—多个生产者、多个消费者在内部使用一个阵列,限制容量

原子队列

前面提到的所有队列都使用sun.misc.Unsafe. 然而,随着java9和JEP-260的出现,这个API在默认情况下变得不可访问。

因此,有其他队列使用java.util.concurrent.atomic.AtomicLongFieldUpdater(公共API,性能较差)而不是sun.misc.Unsafe.

它们是从上面的队列生成的,它们的名称中间插入了单词Atomic,例如SpscChunkedAtomicArrayQueue或MpmcAtomicArrayQueue。

如果可能,建议使用“常规”队列,并且仅在sun.misc.Unsafe像Hot Java9+和JRockit一样被禁止/无效。

容量

所有JCTools队列也可能具有最大容量或未绑定。当队列已满且受容量限制时,它将停止接受新元素。

在以下示例中,我们:

  • 填满队列
  • 确保在此之后停止接受新元素
  • 从中排出,并确保之后可以添加更多元素

请注意,为了可读性,删除了几个代码语句。


SpscChunkedArrayQueue<Integer> queue = new SpscChunkedArrayQueue<>(8, 16);
CountDownLatch startConsuming = new CountDownLatch(1);
CountDownLatch awakeProducer = new CountDownLatch(1);

Thread producer = new Thread(() -> {
  IntStream.range(0, queue.capacity()).forEach(i -> {
    assertThat(queue.offer(i)).isTrue();
  });
  assertThat(queue.offer(queue.capacity())).isFalse();
  startConsuming.countDown();
  awakeProducer.await();
  assertThat(queue.offer(queue.capacity())).isTrue();
});

producer.start();
startConsuming.await();

Set<Integer> fromQueue = new HashSet<>();
queue.drain(fromQueue::add);
awakeProducer.countDown();
producer.join();
queue.drain(fromQueue::add);

assertThat(fromQueue).containsAll(
 IntStream.range(0, 17).boxed().collect(toSet()));

其他数据结构工具

JCTools还提供了一些非队列数据结构。

它们都列在下面:

  • NonBlockingHashMap–一个无锁的ConcurrentHashMap替代方案,具有更好的伸缩性和通常更低的突变成本。它是实现sun.misc.Unsafe,因此,不建议在Java9+或JRockit环境中使用此类
  • NonBlockingHashMapLong–与NonBlockingHashMap类似,但使用基本长键
  • NonBlockingHashSet–一个简单的包装器,围绕着像jdk的java.util.Collections.newSetFromMap()一样的NonBlockingHashMap
  • NonBlockingIdentityHashMap–与NonBlockingHashMap类似,但按标识比较键。
  • NonBlockingSetInt–一个多线程位向量集,实现为一个原始long数组。在无声自动装箱的情况下工作无效

性能测试

让我们使用JMH来比较JDK的ArrayBlockingQueue和JCTools队列的性能。JMH是Sun/oracle JVM gurus提供的一个开源微基准框架,它保护我们不受编译器/JVM优化算法的不确定性的影响。

请注意,为了提高可读性,下面的代码段遗漏了几个语句。


public class MpmcBenchmark {

  @Param({PARAM_UNSAFE, PARAM_AFU, PARAM_JDK})
  public volatile String implementation;

  public volatile Queue<Long> queue;

  @Benchmark
  @Group(GROUP_NAME)
  @GroupThreads(PRODUCER_THREADS_NUMBER)
  public void write(Control control) {
    // noinspection StatementWithEmptyBody
    while (!control.stopMeasurement && !queue.offer(1L)) {
      // intentionally left blank
    }
  }

  @Benchmark
  @Group(GROUP_NAME)
  @GroupThreads(CONSUMER_THREADS_NUMBER)
  public void read(Control control) {
    // noinspection StatementWithEmptyBody
    while (!control.stopMeasurement && queue.poll() == null) {
      // intentionally left blank
    }
  }
}

结果:


MpmcBenchmark.MyGroup:MyGroup·p0.95 MpmcArrayQueue sample 1052.000 ns/op
MpmcBenchmark.MyGroup:MyGroup·p0.95 MpmcAtomicArrayQueue sample 1106.000 ns/op
MpmcBenchmark.MyGroup:MyGroup·p0.95 ArrayBlockingQueue sample 2364.000 ns/op

我们可以看到,MpmcArrayQueue的性能略好于MpmcAtomicArrayQueue,而ArrayBlockingQueue的速度慢了两倍。

使用JCTools的缺点

使用JCTools有一个重要的缺点——不可能强制正确使用库类。例如,考虑在我们的大型成熟项目中开始使用MpscArrayQueue的情况(注意,必须有一个使用者)。

不幸的是,由于项目很大,有可能有人出现编程或配置错误,现在从多个线程读取队列。这个系统看起来像以前一样工作,但现在有可能消费者错过了一些信息。这是一个真正的问题,可能会有很大的影响,是很难调试。

理想情况下,应该可以运行具有特定系统属性的系统,该属性强制JCTools确保线程访问策略。例如,本地/测试/暂存环境(而不是生产环境)可能已启用它。遗憾的是,JCTools没有提供这样的属性。

另一个需要考虑的问题是,尽管我们确保JCTools比JDK的对应工具快得多,但这并不意味着我们的应用程序获得了与我们开始使用自定义队列实现时相同的速度。大多数应用程序不会在线程之间交换很多对象,而且大多是I/O绑定的。

结论

现在,我们对JCTools提供的实用程序类有了基本的了解,并了解了它们在重载下与JDK的对应类相比的性能。

总之,只有当我们在线程之间交换大量对象时,才有必要使用该库,即使这样,也有必要非常小心地保留线程访问策略。

以上示例的完整源代码地址:https://GitHub.com/eugenp/tutorials/tree/master/libraries-5

JCTools git地址:Https://github.com/JCTools/JCTools

以上就是如何使用JCTools实现Java并发程序的详细内容,更多关于使用JCTools实现Java并发程序的资料请关注编程网其它相关文章!

--结束END--

本文标题: 如何使用JCTools实现Java并发程序

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

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

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何使用JCTools实现Java并发程序
    目录概述非阻塞算法依赖JCTools队列队列实现原子队列容量其他数据结构工具性能测试使用JCTools的缺点结论概述 在本文中,我们将介绍JCTools(Java并发工具)库。 简...
    99+
    2024-04-02
  • 利用JCTools怎么实现Java并发程序
    本篇文章给大家分享的是有关利用JCTools怎么实现Java并发程序,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。非阻塞算法传统上,在可变共享状态下工作的多线程代码使用锁来确保...
    99+
    2023-06-14
  • Java如何实现并发编程?
    Java如何实现并发编程? 在今天的软件开发领域中,多核处理器已经成为了主流。因此,实现并发编程已经成为了必要的技能。Java是一种支持并发编程的编程语言,它提供了一些重要的工具和API来帮助开发人员实现并发编程。本文将介绍Java中实现并...
    99+
    2023-08-28
    numy shell 并发
  • 如何使用Go开发并发程序
    这篇文章主要介绍如何使用Go开发并发程序,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!我们都知道计算机的核心为 CPU,它是计算机的运算和控制核心,承载了所有的计算任务。最近半个世纪...
    99+
    2024-04-02
  • Java应用程序如何实现高效响应和并发性?
    Java是一种广泛使用的编程语言,应用程序开发者常常需要实现高效响应和并发性。如何达到这个目标呢?本文将介绍一些实现高效响应和并发性的技巧和最佳实践。 一、使用线程池 Java中的线程池是一种重要的并发编程技术。线程池可以在创建线程时为线程...
    99+
    2023-11-06
    响应 并发 spring
  • 如何使用NPM在Java和NumPy中实现并发编程?
    随着计算机科学的不断发展,多核处理器的出现使得并发编程成为了一种重要的编程方式。并发编程可以大大提高程序的性能和响应能力,减少等待时间,提高程序的可靠性。但是,并发编程也面临着很多挑战,如竞态条件、死锁等问题。为了解决这些问题,我们需要使...
    99+
    2023-07-23
    numy 并发 npm
  • 使用Java如何实现ConcurrentHashMap#put并发容器
    使用Java如何实现ConcurrentHashMap#put并发容器?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。jdk1.7.0_79HashMap可以说是每个Java...
    99+
    2023-05-31
    java 并发容器
  • Java中如何使用NumPy实现并发计算?
    Java是一门功能强大的编程语言,能够用于开发各种类型的应用程序。而NumPy则是一种用于数学计算的Python库,它可以帮助开发者进行高效的数组计算。本文将介绍如何在Java中使用NumPy实现并发计算。 一、Java中使用NumPy的...
    99+
    2023-07-23
    numy 并发 npm
  • 如何使用 Java 和 Bash 实现高效并发?
    随着计算机技术的不断发展,我们需要处理的数据量越来越大,对并发处理的需求也越来越迫切。Java 和 Bash 是常用的编程语言,在处理并发任务方面都有很好的支持。本文将介绍如何使用 Java 和 Bash 实现高效并发。 Java 实现并...
    99+
    2023-10-12
    bash 并发 日志
  • Java中的并发编程:如何使用ConcurrentLinkedQueue实现线程安全?
    在Java中,我们经常需要使用多线程来提高程序的运行效率。但是多线程编程也会带来线程安全的问题,其中一个常见的问题就是多个线程同时操作同一个数据结构,可能会出现数据不一致或者数据丢失等问题。为了解决这个问题,Java提供了多种线程安全的数...
    99+
    2023-09-19
    并发 数组 容器
  • Java和Git如何实现并发编程?
    随着现代软件开发项目的复杂性不断增加,编写高效的并发程序变得至关重要。Java和Git是两个非常流行的编程工具,它们都有一些强大的特性,可以帮助我们实现并发编程。 Java并发编程 Java是一种广泛使用的面向对象编程语言,它提供了大量的...
    99+
    2023-10-16
    git django 并发
  • Spring并发编程:如何使用Java语言实现多线程响应?
    随着计算机技术的不断发展,多核CPU已经成为了现代计算机的标配。针对多核CPU的并发编程已经成为了开发人员不可回避的问题。在Java语言中,提供了多线程机制来支持并发编程。本文将为大家介绍如何使用Java语言实现多线程响应。 一、基本概念...
    99+
    2023-11-06
    响应 并发 spring
  • 如何在Java中利用CyclicBarrier实现并发编程
    如何在Java中利用CyclicBarrier实现并发编程?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。  使用JAVA编写并发程序的时候,我们需要仔...
    99+
    2023-05-31
    java 并发编程 cyclicbarrier
  • Java中,如何使用数组实现并发接口?
    在Java编程中,数组是一种非常常见的数据结构。同时,在多线程编程中,并发接口也是必不可少的。那么,在Java中,如何使用数组实现并发接口呢?本文将从以下几个方面进行介绍: Java中的并发接口 在Java中,有很多种并发接口,例如:...
    99+
    2023-06-24
    数组 接口 并发
  • 如何在ASP.NET应用程序中实现并发控制?
    在ASP.NET应用程序中实现并发控制是一个非常重要的问题。在这个过程中,我们需要考虑多个用户同时访问应用程序的情况,以确保应用程序在高负载下能够正常运行。 一、 什么是并发控制? 并发控制是指在多个用户同时访问应用程序时,通过一些手段来确...
    99+
    2023-07-20
    并发 spring 日志
  • 如何使用Java高并发编程CyclicBarrier
    本篇内容介绍了“如何使用Java高并发编程CyclicBarrier”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!什么是CyclicBarr...
    99+
    2023-06-15
  • PHP8.0如何使用Fibers实现并发
    随着现代互联网技术的不断发展,网站访问量越来越大,对于服务器的并发处理能力也提出了更高的要求。如何提高服务器的并发处理能力是每个开发者需要面对的问题。在这个背景下,PHP8.0引入了Fibers这一全新的特性,让PHP开发者掌握一种全新的并...
    99+
    2023-05-14
    PHP 并发 Fibers
  • 如何在Java中使用并发容器和线程池来提高程序的并发性?
    Java作为一种高级编程语言,提供了许多并发编程的工具和机制,其中包括并发容器和线程池。使用这些工具可以提高程序的并发性,从而使得程序更加高效。 一、并发容器 Java提供了许多并发容器,这些容器具有线程安全的特性,可以让多个线程同时访问容...
    99+
    2023-09-19
    并发 数组 容器
  • java多线程中如何实现线程并发库
    本篇文章给大家分享的是有关java多线程中如何实现线程并发库,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。多线程之线程并发库原子性操作类java.util.concurrent...
    99+
    2023-06-19
  • 如何使用Java和Git实现Django的并发控制?
    Django是一个流行的Python web框架,它以简单易用和高效稳定著称。然而,在高并发的情况下,Django可能会遇到一些性能问题。这时,使用Java和Git来实现Django的并发控制是一个不错的选择。本文将介绍如何使用Java和...
    99+
    2023-10-16
    git django 并发
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作