背景
大文件生成,分别采用了三种模式,进行测试。
单线程
多线程+阻塞队列
Disruptor
测试结果
上源码
public class BigFileWrite {
public static final AtomicInteger COUNT = new AtomicInteger(10000000);
public static LinkedBlockingQueue<String> concurrentLinkedQueue = new LinkedBlockingQueue<>();
public byte[] lock = new byte[1];
public static final int RPODUCE_NUM = 4;
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(8, 8,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>());
@Test
public void writeTest() {
FileWriter writer = null;
try {
writer = new FileWriter("D:\\logs\\test.txt");
for (int i = 0; i < COUNT.get(); i++) {
writer.append(JSON.toJSONString(Upc.getInstance()));
writer.append("\n");
}
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void syncWriteTest() throws InterruptedException {
FileWriter writer = null;
try {
writer = new FileWriter("D:\\logs\\test.txt");
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < RPODUCE_NUM; i++) {
threadPoolExecutor.execute(() -> {
while (COUNT.getAndDecrement() > 0) {
concurrentLinkedQueue.add(JSON.toJSONString(Upc.getInstance()));
}
});
}
int threadNum = 2;
CountDownLatch downLatch = new CountDownLatch(threadNum);
for (int i = 0; i < threadNum; i++) {
FileWriter finalWriter = writer;
threadPoolExecutor.execute(() -> {
while (COUNT.get() > 0 || concurrentLinkedQueue.size() > 0) {
try {
String result = concurrentLinkedQueue.poll();
if (null != result) {
finalWriter.append(result);
finalWriter.append("\n");
}
} catch (Exception e) {
e.printStackTrace();
}
}
downLatch.countDown();
});
}
downLatch.await();
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void syncDisruptorTest() {
FileWriter writer = null;
try {
writer = new FileWriter("D:\\logs\\test.txt");
} catch (IOException e) {
e.printStackTrace();
}
CountDownLatch downLatch = new CountDownLatch(COUNT.get());
// Specify the size of the ring buffer, must be power of 2.
int bufferSize = 2048;
// Construct the Disruptor
Disruptor<StringEvent> disruptor = new Disruptor<>(StringEvent::new,
bufferSize,
DaemonThreadFactory.INSTANCE,
ProducerType.MULTI,
new YieldingWaitStrategy());
StringEventHandler stringEventHandler = new StringEventHandler(downLatch, writer);
// Connect the handler
disruptor.handleEventsWith(stringEventHandler, stringEventHandler);
// Start the Disruptor, starts all threads running
disruptor.start();
// Get the ring buffer from the Disruptor to be used for publishing.
RingBuffer<StringEvent> ringBuffer = disruptor.getRingBuffer();
//模拟多个生产者
for (int i = 0; i < RPODUCE_NUM; i++) {
final int a = i;
threadPoolExecutor.execute(() ->
//将ringBuffer 和 生产者ID传入
new Producer(ringBuffer, a).process()
);
}
try {
downLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Data
static class StringEventHandler implements EventHandler<StringEvent> {
private StringEventHandler(){}
public StringEventHandler(CountDownLatch countDownLatch, FileWriter writer) {
this.writer = writer;
this.countDownLatch = countDownLatch;
}
private CountDownLatch countDownLatch;
private FileWriter writer;
public void onEvent(StringEvent event, long sequence, boolean endOfBatch) {
try {
writer.append(event.getInfo());
writer.append("\n");
} catch (IOException e) {
e.printStackTrace();
}
countDownLatch.countDown();
}
}
@Data
static class StringEvent {
private String info;
}
static class Producer {
private RingBuffer<StringEvent> ringBuffer;
private Integer produceId;
public static void translate(StringEvent event, long sequence, String buffer) {
event.setInfo(buffer);
}
public Producer(RingBuffer<StringEvent> ringBuffer, Integer produceId) {
this.ringBuffer = ringBuffer;
this.produceId = produceId;
}
public void process(){
for (int l = 0; l < COUNT.get() / RPODUCE_NUM; l++) {
ringBuffer.publishEvent(Producer::translate, JSON.toJSONString(Upc.getInstance()));
}
}
}
}