从多个线程以随机顺序写入文件

时间:2017-06-28 19:53:32

标签: java multithreading bufferedwriter

我有20个并行运行的线程。每个人都调用函数,获取200条记录并写入文件。我想随机化所有记录。有没有什么方法可以用这样的方式写入文件:我从一个线程获得10条记录,然后从下一条线程获得10条,依此类推?

1 个答案:

答案 0 :(得分:0)

  

我是否有办法以这样的方式写入文件,即从一个线程获得10条记录,然后从下一条线程获得10条,依此类推?

如果我理解正确,你的问题是如何协调多个线程的输出,以便每个线程按特定顺序打印输出。

在这种情况下,我会使用" Queue"协调线程的工作。像票务系统这样的东西。如果队列的头部对应于线程id / name,那么该线程可以打印其输出(当它完成时,它将从队列的头部删除它的名称。)

单独的协调员将决定允许线程打印其输出的顺序。

例如:

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.*;
import java.util.stream.IntStream;

/**
 * 
 */
public class SchedulerExample {

    public static final int BATCH_LINES = 3;

    public static void main(String[] args) throws InterruptedException {
        SchedulerExample schedulerExample = new SchedulerExample();
        schedulerExample.doTheWork();
    }

    private void doTheWork() throws InterruptedException {


        ExecutorService executorService = Executors.newFixedThreadPool(5);

        Queue<String> queue = new ConcurrentLinkedQueue<>();

        List<String> allowedWorkersNames = new ArrayList<>();
        allowedWorkersNames.add("worker1");
        allowedWorkersNames.add("worker2");
        allowedWorkersNames.add("worker3");

        executorService.submit(new Coordinator(allowedWorkersNames, queue));
        executorService.submit(new Worker("worker1", queue, BATCH_LINES));
        executorService.submit(new Worker("worker2", queue, BATCH_LINES));
        executorService.submit(new Worker("worker3", queue, BATCH_LINES));

        Thread.sleep(10000);

        System.out.println("ending application");
        executorService.shutdownNow();
        executorService.awaitTermination(5, TimeUnit.SECONDS);

    }
}

/**
 * this class decides the order in which workers are allowed to print their outputs
 */
class Coordinator implements Callable<Void> {
    private List<String> allowedWorkersNames = new ArrayList<>();
    private Queue<String> queue;

    public Coordinator(List<String> allowedWorkersNames, Queue<String> queue) {
        this.allowedWorkersNames = allowedWorkersNames;
        this.queue = queue;
    }

    @Override
    public Void call() throws Exception {
        while (true) {
            if (queue.size() == 0) {
                queue.addAll(allowedWorkersNames);
            }
            Thread.sleep(1000);
        }
    }
}

class Worker implements Runnable {

    private String name;
    private int linesCounter;
    private Queue<String> queue;
    private int batchLines;

    public Worker(String name, Queue<String> queue, int batchLines) {
        this.name = name;
        this.queue = queue;
        this.batchLines = batchLines;
    }

    @Override
    public void run() {
        while (true) {

            // do some useful work here.
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                System.out.println(name + "was interrupted");
            }

            // now this thread is ready to print its output.
            String currentHeadOfQueue = queue.peek();
            if (currentHeadOfQueue != null && currentHeadOfQueue.compareTo(name) == 0) {


                IntStream.rangeClosed(1, batchLines).
                        forEach(i -> {
                                    linesCounter++;
                                    System.out.println(name + " - line:" + linesCounter);
                                }
                        );

                queue.remove();
            }
        }
    }
}