总览
Exchanger类在线程之间传递工作和回收使用的对象方面非常有效。 AFAIK,它也是最少使用的并发类之一。
但是,如果您不需要GC,则使用ArrayBlockingQueue进行日志记录会更简单。
交换器类
Exchanger类对于在两个线程之间来回传递数据很有用。 例如生产者/消费者。 它具有自然回收用于传递工作的数据结构的特性,并以有效的方式支持无GC的工作共享。
这是一个将日志传递到后台记录器的示例。
工作(日志条目)被批处理到LogEntries中,并传递给后台线程,该线程随后又将其传递回线程,以便它可以添加更多工作。 如果后台线程始终在批处理完成之前完成,则它几乎是透明的。 批处理大小的增加会减少批处理已满的频率,但会增加任何一次等待的未处理条目的数量。 调用flush()可以推出数据。
关键行如下,它将当前线程中的批处理与另一个线程中的批处理交换。 生产者在消费者清空时填充批次。
交换发生时通常需要1-4微秒。 在这种情况下,每64行一次。
entries = logEntriesExchanger.exchange(entries);
交换器示例
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class BackgroundLogger implements Runnable {static final int ENTRIES = 64;static class LogEntry {long time;int level;final StringBuilder text = new StringBuilder();}static class LogEntries {final LogEntry[] lines = new LogEntry[ENTRIES];int used = 0;}private final ExecutorService executor = Executors.newSingleThreadExecutor();final Exchanger<LogEntries> logEntriesExchanger = new Exchanger<LogEntries>();LogEntries entries = new LogEntries();BackgroundLogger() {executor.submit(this);}public StringBuilder log(int level) {try {if (entries.used == ENTRIES)entries = logEntriesExchanger.exchange(entries);LogEntry le = entries.lines[entries.used++];le.time = System.currentTimeMillis();le.level = level;return le.text;} catch (InterruptedException e) {throw new RuntimeException(e);}}public void flush() throws InterruptedException {if(entries.used > 0)entries = logEntriesExchanger.exchange(entries);}public void stop() {try {flush();} catch (InterruptedException e) {e.printStackTrace(); // use standard logging.}executor.shutdownNow();}@Overridepublic void run() {LogEntries entries = new LogEntries();try {while (!Thread.interrupted()) {entries = logEntriesExchanger.exchange(entries);for (int i = 0; i < entries.used; i++) {bgLog(entries.lines[i]);entries.lines[i].text.delete(0, entries.lines[i].text.length());}entries.used = 0;}} catch (InterruptedException ignored) {} finally {System.out.println("Warn: logger stopping."); // use standard logging.}}private void bgLog(LogEntry line) {// log the entry to a file.}
}
参考:来自Vanilla Java的 JCG合作伙伴 Peter Lawrey 的Exchanger和无GC的 Java 。
相关文章:
- Java中的低GC:使用原语而不是包装器
- Java Lambda语法替代
- JVM如何处理锁
- Erlang与Java内存架构
- Java Fork / Join进行并行编程
- Java最佳实践系列
- 如何在Java中获得类似于C的性能
翻译自: https://www.javacodegeeks.com/2011/09/exchanger-and-gc-less-java.html