java.util.concurrent包(7)——Exchanger使用

简介:
Java 并发 API 提供了一种允许2个并发任务间相互交换数据的同步应用。更具体的说,Exchanger类允许在2个线程间定义同步点,当2个线程到达这个点,他们相互交换数据类型,使用第一个线程的数据类型变成第二个的,然后第二个线程的数据类型变成第一个的。

示例1
一个人有零食,另一个人有钱,他们两个想等价交换,对好口号在某个地方相见,一个人先到了之后,必须等另一个人带着需要的东西来了之后,才能开始交换。
public class ExchangerTest
{
public static void main(String[] args)
{
ExecutorService service = Executors.newCachedThreadPool();
final Exchanger<String> exchanger = new Exchanger<String>();
service.execute(new Runnable()
{
public void run()
{
try
{
String data1 = "零食";
System.out.println("线程" + Thread.currentThread().getName() + "正在把数据" + data1 + "换出去");
Thread.sleep((long) (Math.random() * 1000));
String data2 = exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为" + data2);
}
catch (Exception e)
{
}
}
});

service.execute(new Runnable()
{
public void run()
{
try
{
String data1 = "钱";
System.out.println("线程" + Thread.currentThread().getName() + "正在把数据" + data1 + "换出去");
Thread.sleep((long) (Math.random() * 1000));
String data2 = exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为" + data2);
}
catch (Exception e)
{
}
}
});
}
}
线程pool-1-thread-1正在把数据零食换出去
线程pool-1-thread-2正在把数据钱换出去
线程pool-1-thread-2换回的数据为零食
线程pool-1-thread-1换回的数据为钱


示例2
这个类在遇到类似生产者和消费者问题时,是非常有用的。来一个非常经典的并发问题:你有相同的数据buffer,一个或多个数据生产者,和一个或多个数据消费者。只是Exchange类只能同步2个线程,所以你只能在你的生产者和消费者问题中只有一个生产者和一个消费者时使用这个类。
public class Producer implements Runnable
{

// 要被相互交换的数据类型。
private List<String> buffer;

// 用来同步 producer和consumer
private final Exchanger<List<String>> exchanger;

public Producer(List<String> buffer, Exchanger<List<String>> exchanger)
{
this.buffer = buffer;
this.exchanger = exchanger;
}

public void run()
{
// 实现10次交换
for (int i = 0; i < 10; i++)
{
buffer.add("第" + i + "次生产者的数据" + i);
try
{
// 调用exchange方法来与consumer交换数据
System.out.println("第" + i + "次生产者在等待.....");
buffer = exchanger.exchange(buffer);
System.out.println("第" + i + "次生产者交换后的数据:" + buffer.get(i));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}


public class Consumer implements Runnable
{

// 用来相互交换
private List<String> buffer;

// 用来同步 producer和consumer
private final Exchanger<List<String>> exchanger;

public Consumer(List<String> buffer, Exchanger<List<String>> exchanger)
{
this.buffer = buffer;
this.exchanger = exchanger;
}

public void run()
{
// 实现10次交换
for (int i = 0; i < 10; i++)
{
buffer.add("第" + i + "次消费者的数据" + i);
try
{
// 调用exchange方法来与consumer交换数据
System.out.println("第" + i + "次消费者在等待.....");
buffer = exchanger.exchange(buffer);
System.out.println("第" + i + "次消费者交换后的数据:" + buffer.get(i));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}

public class Core
{
public static void main(String[] args)
{
// 创建2个buffers,分别给producer和consumer使用
List<String> buffer1 = new ArrayList<String>();
List<String> buffer2 = new ArrayList<String>();

// 创建Exchanger对象,用来同步producer和consumer
Exchanger<List<String>> exchanger = new Exchanger<List<String>>();

// 创建Producer对象和Consumer对象
Producer producer = new Producer(buffer1, exchanger);
Consumer consumer = new Consumer(buffer2, exchanger);

// 创建线程来执行producer和consumer并开始线程
Thread threadProducer = new Thread(producer);
Thread threadConsumer = new Thread(consumer);
threadProducer.start();
threadConsumer.start();
}
}
Exchanger 类有另外一个版本的exchange方法
exchange(V data, long time, TimeUnit unit)
V是声明参数种类,例子中是List
此线程会休眠直到另一个线程到达并中断它,或者特定的时间过去了
TimeUnit类有多种常量,DAYS、HOURS、MICROSECONDS、MILLISECONDS、MINUTES、NANOSECONDS和SECONDS

原帖地址:
http://blog.csdn.net/howlaa/article/details/19853447
http://ifeve.com/thread-synchronization-utilities-8/
目录
相关文章
|
3月前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
4月前
|
安全 Java 调度
解锁Java并发编程高阶技能:深入剖析无锁CAS机制、揭秘魔法类Unsafe、精通原子包Atomic,打造高效并发应用
【8月更文挑战第4天】在Java并发编程中,无锁编程以高性能和低延迟应对高并发挑战。核心在于无锁CAS(Compare-And-Swap)机制,它基于硬件支持,确保原子性更新;Unsafe类提供底层内存操作,实现CAS;原子包java.util.concurrent.atomic封装了CAS操作,简化并发编程。通过`AtomicInteger`示例,展现了线程安全的自增操作,突显了这些技术在构建高效并发程序中的关键作用。
77 1
|
1月前
|
Java Android开发
Eclipse 创建 Java 包
Eclipse 创建 Java 包
33 1
|
2月前
|
Java Apache Maven
Java/Spring项目的包开头为什么是com?
本文介绍了 Maven 项目的初始结构,并详细解释了 Java 包命名惯例中的域名反转规则。通过域名反转(如 `com.example`),可以确保包名的唯一性,避免命名冲突,提高代码的可读性和逻辑分层。文章还讨论了域名反转的好处,包括避免命名冲突、全球唯一性、提高代码可读性和逻辑分层。最后,作者提出了一个关于包名的问题,引发读者思考。
101 0
Java/Spring项目的包开头为什么是com?
|
6月前
|
druid Java Maven
杨校老师课堂之java_关于如何下载jar包的教程
杨校老师课堂之java_关于如何下载jar包的教程
128 0
|
3月前
|
Java API 数据处理
Java 包(package)的作用详解
在 Java 中,包(package)用于组织和管理类与接口,具有多项关键作用:1)系统化组织代码,便于理解和维护;2)提供命名空间,避免类名冲突;3)支持访问控制,如 public、protected、默认和 private,增强封装性;4)提升代码可维护性,实现模块化开发;5)简化导入机制,使代码更简洁;6)促进模块化编程,提高代码重用率;7)管理第三方库,避免命名冲突;8)支持 API 设计,便于功能调用;9)配合自动化构建工具,优化项目管理;10)促进团队协作,明确模块归属。合理运用包能显著提升代码质量和开发效率。
239 4
|
3月前
|
Java 数据安全/隐私保护
Java 包(package)的使用详解
Java中的包(`package`)用于组织类和接口,避免类名冲突并控制访问权限,提升代码的可维护性和可重用性。通过`package`关键字定义包,创建相应目录结构即可实现。包可通过`import`语句导入,支持导入具体类或整个包。Java提供多种访问权限修饰符(`public`、`protected`、`default`、`private`),以及丰富的标准库包(如`java.lang`、`java.util`等)。合理的包命名和使用对大型项目的开发至关重要。
199 2
|
4月前
|
JavaScript Java API
Java日志通关(二) - Slf4j+Logback 整合及排包
作者日常在与其他同学合作时,经常发现不合理的日志配置以及五花八门的日志记录方式,后续作者打算在团队内做一次Java日志的分享,本文是整理出的系列文章第二篇。
|
4月前
|
Java Maven 数据库
|
4月前
|
Java
Java应用结构规范问题之在biz层的convert包实现转换的问题如何解决
Java应用结构规范问题之在biz层的convert包实现转换的问题如何解决