如何通过示例使用Java中的Exchanger - Go语言中文社区

如何通过示例使用Java中的Exchanger


大家好,如果您在并发Java应用程序中工作,那么您可能听说过java.util.concurrent包的Exchanger类。 Java中的Exchanger是Java 1.5中与CountDownLatchCyclicBarrierSemaphores一起引入的另一个并发或同步实用程序。 顾名思义, Exchanger允许两个线程在集合点或集合点见面并交换数据。 的
java.util.Exchanger是一个参数类,它定义并保存要交换的对象的类型。 它有一个重载的方法,称为 exchange() ,用于在线程之间交换对象。 这是一种阻塞方法,这意味着线程将调用 exchange()方法在交换点等待,直到另一个线程到达。 一旦另一个线程到达,两个线程都交换对象并从此方法返回。 交换方法的重载版本接受其他 TimeUnit对象,并等待直到超时。

顺便说一句,您还可以中断在交换点等待其他参与者的线程。 与CountDownLatchCyclicBarrierSemaphoreExchanger实用程序只能同步两个线程,这使其非常适合解决经典的生产者-消费者问题

在本Java并发教程中,您将通过使用Exchanger实现生产者-消费者设计模式来学习如何在Java中使用Exchanger。 顺便说一句,我假设您熟悉Java编程语法和语义,如果您是Java的完整入门者,那么您可能会很难理解这个示例。

Exchanger类是一个易于理解和使用的简单同步实用程序。 在最后的两个并发教程中,我们使用了wait和notify解决了生产者使用者(请参阅此处 ),还使用BlockingQueue实现了生产者-消费者 ,现在该使用Exchanger来实现了。

在此Java并发性教程中, 我们将创建一个生产者和一个使用者线程 ,它们将使用Exchanger实用程序类交换缓冲区。

通常,这是Exchanger的工作方式:

1.首先,创建一个Exchange对象,例如Exchanger<Deque<Long>> stringExchanger = new Exchanger<>() ; 这定义了线程之间将交换什么类型的对象。 在这种情况下,两个线程将交换包含长值的Deque对象。

2.当线程A准备交换其缓冲区或对象时,它将调用
Exchanger.exchange()方法。 这是一种阻塞方法线程A将被阻塞,直到线程B到来并将其对象传输到线程A 为止,否则线程A被中断或超时。

3.线程B准备就绪时,它还会调用exchange()方法。 现在,线程A和B互相交换对象,并从交换方法返回。

4.交换完成后,线程A具有线程B的对象,反之亦然。

同样,我想强调Java并发技能的重要性,并敦促每个Java开发人员花一些时间来掌握Java并发类。

带有Exchanger并发的Java程序

 import java.util.ArrayDeque;  import java.util.Deque;  import java.util.concurrent.Exchanger;   /** 
    * Exchanger Example in Java. Exchanger allows two Threads to meet at exchange 
    * point and exchange data structure or objects. In this Java program, exchanger 
    * is used to exchange buffer between producer and consumer.  
   * @author Javin Paul  
   */   public class JavaExchangerTutorail {    
     public static void main(String args[]) throws InterruptedException {   
         //Creating Exchanger to exchange String object with other thread 
          final Exchanger> exchanger = new Exchanger>();   
         Thread producer = new Thread( "Producer : " ){  
             @Override 
              public void run(){  
                 ArrayDeque(); Deque stack = new ArrayDeque();  
                 //producer thread insert elments into stack 
                 while (stack.isEmpty()) { 
 
                     stack.add(System.nanoTime()% 1000 ); 
                     //if stack is not empty then exchange it to consumer thread  
                     try {  
                         System.out.println(Thread.currentThread().getName() 
                                  + " ready to exchange : " + stack); 
 <br> 
 // Exchanger return other Thread's object 
                         stack = exchanger.exchange(stack); 
                         System.out.println(Thread.currentThread().getName() 
                                  + " got : " + stack);  
                     } catch (InterruptedException ie) { ie.printStackTrace(); } (InterruptedException ie) { ie.printStackTrace(); }  
                 }  
             }  
         };    
         Thread consumer = new Thread( "Consumer : " ){  
             @Override  
             public void run(){  
                 ArrayDeque(); Deque stack = new ArrayDeque();   
                 //consumer thread takes object from stack and prints  
                 do { 
                      //if stack is empty then exchange it to producer for refill 
                      try {  
                         System.out.println(Thread.currentThread().getName() 
                                  + " ready to exchange : " + stack); 
                         stack = exchanger.exchange(stack); 
                         System.out.println(Thread.currentThread().getName() 
                                  + " got : " + stack); 
                         stack.remove();  
                     } catch (InterruptedException ie) { ie.printStackTrace(); } (InterruptedException ie) { ie.printStackTrace(); }  
                 } while (stack.isEmpty()) ;    
             }  
         };    
         producer.start(); 
 <br> 
 //sleeping before starting consumer to give producer time to produce 
         Thread.sleep( 1000 ); 
 consumer.start();    
     }     }     Output:   Producer : ready to exchange : [ 247 ]   Consumer : ready to exchange : []   Producer : got : []   Consumer : got : [ 247 ]   Producer : ready to exchange : [ 692 ]   Consumer : ready to exchange : []   Consumer : got : [ 692 ]   Consumer : ready to exchange : []   Producer : got : [] 
 <br> 

代码和输出说明

如果看上面的示例,所有代码都在main方法内部。 之所以使Exchanger实例成为最终实例,是因为我们要从匿名内部类访问它们,并且只能从匿名内部类访问最终局部变量。

后来,我们创建了两个线程, ProducerConsumer 。 生产者检查队列,如果队列为空,则将当前nano时间的最后三位相加并调用exchange()方法。

现在,直到消费者线程到达交换点,我的意思是直到生产者线程调用exchange()方法,生产者线程才会被阻塞。

使用者到达后,双方互相交换堆栈并从exchange()方法返回。 此时,生产者有一个空的消费者堆栈,而消费者有一个非空的生产者堆栈,我的意思是,他们有彼此的对象

为了理解哪个线程正在交换哪个堆栈,我们在每个线程交换之前和之后打印堆栈的内容。 如果您查看输出,这是不言自明的。

顺便提一下,与线程一样,不能保证以相同的顺序获得输出。 在第三次迭代中,您可以看到使用者具有一个已清空的堆栈,甚至可以在安排生产者线程并从交换方法返回之前,准备交换空堆栈。

这就是如何在Java中使用Exchanger的全部内容。 交换器类是一个很好的简单同步工具,非常适合于协调两个线程。 应该使用交换器来实现具有一个生产者和一个消费者的生产者-消费者模式。 如果您想了解有关Java并发类的更多信息,建议您检查以下资源:

进阶学习
完整的Java Masterclass Java多线程,并发和性能优化 Java并发实践–本书 将并发和多线程应用于常见的Java模式

您可能喜欢的其他Java并发文章

  • 2020 Java开发人员路线图路线图
  • Java并发之前发生了什么? ( 回答
  • 10个Java多线程和并发最佳实践( 文章
  • Java中的前50个多线程和并发问题( 问题
  • 掌握Java并发性的5大书籍( 书籍
  • 10个面向初学者和中级开发者的免费Java课程( 课程
  • 如何避免Java死锁? ( 回答
  • 了解Java程序中的数据和代码流( 回答
  • Java Concurrency in Practice是否在2020年仍然有效( 回答
  • Java中CyclicBarrier和CountDownLatch之间的区别? ( 回答
  • 10个技巧,成为2020年的一个更好的Java开发( 提示
  • 如何使用wait-notify在Java中进行线程间通信? ( 回答
  • 深入学习Java多线程的前5门课程( 课程

感谢您到目前为止阅读本文。 如果您喜欢此Java并发教程,请与您的朋友和同事分享。 如果您有任何问题或反馈,请留下笔记。

PS –如果您是Java世界的新手,并且想与Concurrency一起学习核心概念,但是想找一些免费的入门课程,那么您也可以在Udemy上查看此免费的Java Multithreading课程 。 这也是学习Java并发性的一门很好的免费课程。

翻译自: https://www.javacodegeeks.com/2020/05/how-to-use-exchanger-in-java-with-example.html

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/dnc8371/article/details/106699744
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-04-12 05:42:58
  • 阅读 ( 671 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢