【并发技术16】线程同步工具Exchanger的使用

简介: 【并发技术16】线程同步工具Exchanger的使用

如果两个线程在运行过程中需要交换彼此的信息,比如一个数据或者使用的空间,就需要用到 Exchanger 这个类,Exchanger 为线程交换信息提供了非常方便的途径,它可以作为两个线程交换对象的同步点,只有当每个线程都在进入 exchange() 方法并给出对象时,才能接受其他线程返回时给出的对象。

每次只能两个线程交换数据,如果有多个线程,也只有两个能交换数据。下面看个通俗的例子:一手交钱一首交货!

public class ExchangerTest { 
    public static void main(String[] args) { 
        ExecutorService service = Executors.newCachedThreadPool(); 
        final Exchanger exchanger = new Exchanger(); //定义一个交换对象,用来交换数据       
        //开启一个线程执行任务
        service.execute(new Runnable(){             
            @Override
            public void run() { 
                try {                
                    String data1 = "海洛因"; 
                    System.out.println("线程" + Thread.currentThread().getName() 
                            + "正在把毒品" + data1 + "拿出来");                    
                    Thread.sleep((long)(Math.random()*10000)); 
                  //把要交换的数据传到exchange方法中,然后被阻塞,等待另一个线程与之交换。返回交换后的数据
                    String data2 = (String)exchanger.exchange(data1); 
                    System.out.println("线程" + Thread.currentThread().getName() +  
                    "用海洛因换来了" + data2); 
                }catch(Exception e){     
                } finally {
                    service.shutdown();
                    System.out.println("交易完毕,拿着钱快跑!");
                }
            }    
        }); 
        //开启另一个线程执行任务
        service.execute(new Runnable(){             
            @Override
            public void run() { 
                try {                
                    String data1 = "300万"; 
                    System.out.println("线程" + Thread.currentThread().getName() +  
                    "正在把" + data1 +"拿出来"); 
                    Thread.sleep((long)(Math.random()*10000));                       
                    String data2 = (String)exchanger.exchange(data1);                     
                    System.out.println("线程" + Thread.currentThread().getName() +  
                    "用300万弄到了" + data2); 
                }catch(Exception e){     
                } finally {
                    service.shutdown();
                    System.out.println("交易完毕,拿着海洛因快跑!");
                }
            }    
        });         
    } 
}

从代码中我仿佛看到了两个人在交易毒品的场面……来看一下交易结果如何:

线程pool-1-thread-1正在把毒品海洛因拿出来

线程pool-1-thread-2正在把300万拿出来

线程pool-1-thread-2用300万弄到了海洛因

线程pool-1-thread-1用海洛因换来了300万

交易完毕,拿着海洛因快跑!

交易完毕,拿着钱快跑!

跑的倒是快,从运行结果来看,确实实现了数据的交换,这个只是交换一个基本类型的数据而已,它真正的用处不仅仅局限于此,比如我们可以交换一个对象,这就有用了,JDK 官方提到了一个高级的应用:

使用 Exchanger 在线程间交换缓冲区,因此,在需要时,填充缓冲区的线程获取一个新腾空的缓冲区,并将填满的缓冲区传递给腾空缓冲区的线程。

这就得根据实际情况了,思想和上面的一样,实际中肯定要定义一个缓冲区的类,然后两个线程之间交换的就是这个缓冲区的类即可,至于类中如何实现,就得看实际情况了。Exchanger 的使用就总结这么多吧~

如果两个线程在运行过程中需要交换彼此的信息,比如一个数据或者使用的空间,就需要用到 Exchanger 这个类,Exchanger 为线程交换信息提供了非常方便的途径,它可以作为两个线程交换对象的同步点,只有当每个线程都在进入 exchange() 方法并给出对象时,才能接受其他线程返回时给出的对象。

每次只能两个线程交换数据,如果有多个线程,也只有两个能交换数据。下面看个通俗的例子:一手交钱一首交货!

public class ExchangerTest { 
    public static void main(String[] args) { 
        ExecutorService service = Executors.newCachedThreadPool(); 
        final Exchanger exchanger = new Exchanger(); //定义一个交换对象,用来交换数据       
        //开启一个线程执行任务
        service.execute(new Runnable(){             
            @Override
            public void run() { 
                try {                
                    String data1 = "海洛因"; 
                    System.out.println("线程" + Thread.currentThread().getName() 
                            + "正在把毒品" + data1 + "拿出来");                    
                    Thread.sleep((long)(Math.random()*10000)); 
                  //把要交换的数据传到exchange方法中,然后被阻塞,等待另一个线程与之交换。返回交换后的数据
                    String data2 = (String)exchanger.exchange(data1); 
                    System.out.println("线程" + Thread.currentThread().getName() +  
                    "用海洛因换来了" + data2); 
                }catch(Exception e){     
                } finally {
                    service.shutdown();
                    System.out.println("交易完毕,拿着钱快跑!");
                }
            }    
        }); 
        //开启另一个线程执行任务
        service.execute(new Runnable(){             
            @Override
            public void run() { 
                try {                
                    String data1 = "300万"; 
                    System.out.println("线程" + Thread.currentThread().getName() +  
                    "正在把" + data1 +"拿出来"); 
                    Thread.sleep((long)(Math.random()*10000));                       
                    String data2 = (String)exchanger.exchange(data1);                     
                    System.out.println("线程" + Thread.currentThread().getName() +  
                    "用300万弄到了" + data2); 
                }catch(Exception e){     
                } finally {
                    service.shutdown();
                    System.out.println("交易完毕,拿着海洛因快跑!");
                }
            }    
        });         
    } 
}

从代码中我仿佛看到了两个人在交易毒品的场面……来看一下交易结果如何:

线程pool-1-thread-1正在把毒品海洛因拿出来

线程pool-1-thread-2正在把300万拿出来

线程pool-1-thread-2用300万弄到了海洛因

线程pool-1-thread-1用海洛因换来了300万

交易完毕,拿着海洛因快跑!

交易完毕,拿着钱快跑!

跑的倒是快,从运行结果来看,确实实现了数据的交换,这个只是交换一个基本类型的数据而已,它真正的用处不仅仅局限于此,比如我们可以交换一个对象,这就有用了,JDK 官方提到了一个高级的应用:

使用 Exchanger 在线程间交换缓冲区,因此,在需要时,填充缓冲区的线程获取一个新腾空的缓冲区,并将填满的缓冲区传递给腾空缓冲区的线程。

这就得根据实际情况了,思想和上面的一样,实际中肯定要定义一个缓冲区的类,然后两个线程之间交换的就是这个缓冲区的类即可,至于类中如何实现,就得看实际情况了。Exchanger 的使用就总结这么多吧~


相关文章
|
19天前
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
99 0
|
4天前
|
安全
List并发线程安全问题
【10月更文挑战第21天】`List` 并发线程安全问题是多线程编程中一个非常重要的问题,需要我们认真对待和处理。只有通过不断地学习和实践,我们才能更好地掌握多线程编程的技巧和方法,提高程序的性能和稳定性。
|
2天前
|
存储 安全 UED
多线程在打包工具中的运用
【11月更文挑战第2天】本文介绍了多线程技术在打包工具中的应用,包括提高打包效率、优化用户体验和多线程安全考虑。通过并行处理文件和加速资源收集,多线程可以显著缩短打包时间。在用户体验方面,多线程使界面保持响应,并支持优先级处理。此外,文章还讨论了资源访问冲突和死锁预防的解决方案,确保多线程环境下的稳定性和安全性。
|
20天前
|
Java 数据库连接 数据库
不同业务使用同一个线程池发生死锁的技术探讨
【10月更文挑战第6天】在并发编程中,线程池是一种常用的优化手段,用于管理和复用线程资源,减少线程的创建和销毁开销。然而,当多个不同业务场景共用同一个线程池时,可能会引发一系列并发问题,其中死锁就是最为严重的一种。本文将深入探讨不同业务使用同一个线程池发生死锁的原因、影响及解决方案,旨在帮助开发者避免此类陷阱,提升系统的稳定性和可靠性。
38 5
|
17天前
|
Java
【编程进阶知识】揭秘Java多线程:并发与顺序编程的奥秘
本文介绍了Java多线程编程的基础,通过对比顺序执行和并发执行的方式,展示了如何使用`run`方法和`start`方法来控制线程的执行模式。文章通过具体示例详细解析了两者的异同及应用场景,帮助读者更好地理解和运用多线程技术。
22 1
|
18天前
|
网络协议 安全 Java
难懂,误点!将多线程技术应用于Python的异步事件循环
难懂,误点!将多线程技术应用于Python的异步事件循环
46 0
|
2月前
|
网络协议 C语言
C语言 网络编程(十四)并发的TCP服务端-以线程完成功能
这段代码实现了一个基于TCP协议的多线程服务器和客户端程序,服务器端通过为每个客户端创建独立的线程来处理并发请求,解决了粘包问题并支持不定长数据传输。服务器监听在IP地址`172.17.140.183`的`8080`端口上,接收客户端发来的数据,并将接收到的消息添加“-回传”后返回给客户端。客户端则可以循环输入并发送数据,同时接收服务器回传的信息。当输入“exit”时,客户端会结束与服务器的通信并关闭连接。
|
2月前
|
数据采集 消息中间件 并行计算
进程、线程与协程:并发执行的三种重要概念与应用
进程、线程与协程:并发执行的三种重要概念与应用
51 0
|
22天前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
36 1
C++ 多线程之初识多线程
|
6天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
11 3

相关实验场景

更多