java - 在java中以循环方式运行线程

标签 java multithreading synchronization

我是java中多线程和同步的新手。我正在尝试实现一项任务,其中给我 5 个文件,每个文件将由一个特定线程读取。每个线程都应该从文件中读取一行,然后将执行转发到下一个线程,依此类推。当所有 5 个线程都读取第一行时,然后再次从线程 1 开始运行第 1 行。文件 1 的 2 等等。

    Thread ReadThread1 = new Thread(new ReadFile(0));
    Thread ReadThread2 = new Thread(new ReadFile(1));
    Thread ReadThread3 = new Thread(new ReadFile(2));
    Thread ReadThread4 = new Thread(new ReadFile(3));
    Thread ReadThread5 = new Thread(new ReadFile(4));

    // starting all the threads
    ReadThread1.start();
    ReadThread2.start();
    ReadThread3.start();
    ReadThread4.start();
    ReadThread5.start();

在ReadFile(它实现了Runnable)中,在run方法中,我试图在bufferreader对象上进行同步。

        BufferedReader br = null;

            String sCurrentLine;
            String filename="Source/"+files[fileno];
            br = new BufferedReader(new FileReader(filename));

            synchronized(br)
            {

            while ((sCurrentLine = br.readLine()) != null) {
                int f=fileno+1;
                System.out.print("File No."+f);
                System.out.println("-->"+sCurrentLine);
br.notifyAll();
// some thing needs to be dine here i guess 
}}

需要帮助

最佳答案

虽然这不是使用多线程的理想场景,但由于这是作业,我将提供一个可行的解决方案。线程将按顺序执行,有几点需要注意:

  1. 当前线程无法继续读取文件中的行,除非其紧邻的前一个线程已完成(因为它们应该以循环方式读取)。
  2. 当前线程读取完该行后,必须通知另一个线程,否则该线程将永远等待。

我已经使用临时包中的一些文件测试了此代码,它能够以循环方式读取行。我相信Phaser也可以用来解决这个问题。

    public class FileReaderRoundRobinNew {
        public Object[] locks;

        private static class LinePrinterJob implements Runnable {
            private final Object currentLock;


private final Object nextLock;
        BufferedReader bufferedReader = null;

        public LinePrinterJob(String fileToRead, Object currentLock, Object nextLock) {
            this.currentLock = currentLock;
            this.nextLock = nextLock;
            try {
                this.bufferedReader = new BufferedReader(new FileReader(fileToRead));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            /*
             * Few points to be noted:
             * 1. Current thread cannot move ahead to read the line in the file until and unless its immediately previous thread is done as they are supposed to read in round-robin fashion.
             * 2. After current thread is done reading the line it must notify the other thread else that thread will wait forever.
             * */
            String currentLine;
            synchronized(currentLock) {
                try {
                    while ( (currentLine = bufferedReader.readLine()) != null) {
                        try {
                            currentLock.wait();
                            System.out.println(currentLine);
                        }
                        catch(InterruptedException e) {}
                        synchronized(nextLock) {
                            nextLock.notify();
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            synchronized(nextLock) {
                nextLock.notify(); /// Ensures all threads exit at the end
            }
        }
    }

    public FileReaderRoundRobinNew(int numberOfFilesToRead) {
        locks = new Object[numberOfFilesToRead];
        int i;
        String fileLocation = "src/temp/";
        //Initialize lock instances in array.
        for(i = 0; i < numberOfFilesToRead; ++i) locks[i] = new Object();
        //Create threads
        int j;
        for(j=0; j<(numberOfFilesToRead-1); j++ ){
            Thread linePrinterThread = new Thread(new LinePrinterJob(fileLocation + "Temp" + j,locks[j],locks[j+1]));
            linePrinterThread.start();
        }
        Thread lastLinePrinterThread = new Thread(new LinePrinterJob(fileLocation + "Temp" + j,locks[numberOfFilesToRead-1],locks[0]));
        lastLinePrinterThread.start();
    }

    public void startPrinting() {
        synchronized (locks[0]) {
            locks[0].notify();
        }
    }

    public static void main(String[] args) {
        FileReaderRoundRobinNew fileReaderRoundRobin = new FileReaderRoundRobinNew(4);
        fileReaderRoundRobin.startPrinting();
    }
}

如果唯一的目标是以循环方式读取文件而不是严格按照相同的顺序,那么我们也可以使用 Phaser。在这种情况下,读取文件的顺序并不总是相同,例如,如果我们有四个文件(F1、F2、F3 和 F4),那么在第一阶段它可以将它们读取为 F1-F2-F3-F4,但在下一个阶段它可以将它们读取为 F2-F1-F4-F3。为了完成,我仍然放置此解决方案。

public class FileReaderRoundRobinUsingPhaser {

    final List<Runnable> tasks = new ArrayList<>();
    final int numberOfLinesToRead;

    private static class LinePrinterJob implements Runnable {
        private BufferedReader bufferedReader;

        public LinePrinterJob(BufferedReader bufferedReader) {
            this.bufferedReader = bufferedReader;
        }

        @Override
        public void run() {
            String currentLine;
            try {
                currentLine = bufferedReader.readLine();
                System.out.println(currentLine);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public FileReaderRoundRobinUsingPhaser(int numberOfFilesToRead, int numberOfLinesToRead) {
        this.numberOfLinesToRead = numberOfLinesToRead;
        String fileLocation = "src/temp/";
        for(int j=0; j<(numberOfFilesToRead-1); j++ ){
            try {
                tasks.add(new LinePrinterJob(new BufferedReader(new FileReader(fileLocation + "Temp" + j))));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    public void startPrinting( ) {
        final Phaser phaser = new Phaser(1){
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                System.out.println("Phase Number: " + phase +" Registeres parties: " + getRegisteredParties() + " Arrived: " + getArrivedParties());
                return ( phase >= numberOfLinesToRead || registeredParties == 0);
            }
        };

        for(Runnable task : tasks) {
            phaser.register();
            new Thread(() -> {
                do {
                    phaser.arriveAndAwaitAdvance();
                    task.run();
                } while(!phaser.isTerminated());
            }).start();
        }
        phaser.arriveAndDeregister();
    }

    public static void main(String[] args) {
        FileReaderRoundRobinUsingPhaser fileReaderRoundRobin = new FileReaderRoundRobinUsingPhaser(4, 4);
        fileReaderRoundRobin.startPrinting();
        // Files will be accessed in round robin fashion but not exactly in same order always. For example it can read 4 files as 1234 then 1342 or 1243 etc.
    }

}

上面的例子可以根据具体要求进行修改。这里 FileReaderRoundRobinUsingPhaser 的构造函数获取文件数和从每个文件读取的行数。还需要考虑边界条件。

关于java - 在java中以循环方式运行线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18314852/

相关文章:

java - 如何使用java验证XML?

java - JVM 中运行的默认线程数是多少?

python - 为什么不是 numpy.mean 多线程?

python - 在 flask 中使用 Gevent : API is not asynchronous

algorithm - 哪个集群节点应该处于事件状态?

node.js - 同步node.js对象

java - @EnableEurekaClient有什么用?

java - 将二进制文件中的数组输出到程序

java - 使用套接字和线程时出现 EOFException/SocketException

同步滚动多个可滚动小部件