当前位置: 首页 > 知识库问答 >
问题:

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

应安国
2023-03-14

我是java多线程和同步的新手。我试图实现一个任务,其中我给了5个文件,每个文件将由一个特定的线程读取。每个线程应该从文件中读取一行,然后将执行转发给下一个线程,依此类推。当所有5个线程读取第一行时,再次从线程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方法中,我正在尝试在缓冲区读取器对象上同步。

        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 
}}

需要帮助

共有2个答案

夏祺然
2023-03-14

你遗漏了拼图的许多部分:

> < li>

您尝试在每个线程的本地对象上进行同步。这不会有任何影响,JVM甚至可能删除整个锁定操作;

您在没有匹配的< code>wait的情况下执行< code > notify all ;

缺少的etc必须位于run方法的顶部,而不是您所指示的底部。

总之,我担心在这一点上修复代码超出了StackOverflow答案的范围。我的建议是首先熟悉核心概念:Java中锁的语义,它们如何与<code>wait<code>和<code>notify<code>互操作,以及这些方法的精确语义。关于这个主题的甲骨文教程将是一个很好的开始。

隆兴修
2023-03-14

虽然这不是使用多线程的理想场景,但由于这是赋值,我提出了一个有效的解决方案。线程将按顺序执行,需要注意的地方很少:

  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中的多线程和同步的新手。我正在尝试实现一项任务,其中给了我5个文件,每个文件将由一个特定线程读取。每个线程应从文件读取一行,然后将执行转发到下一个线程,依此类推。当所有5个线程都读取第一行时,然后再次从线程1运行行号开始。文件1中的2,依此类推。 并且在ReadFile(在run方法中实现Runnable的情况下,我正在尝试在bufferreader对象上进行同步。 需要帮

  • 问题内容: 我有一个具有1 2 3 4 5值的数组。 现在我想以循环方式遍历它。像我想打印2 3 4 5 1或3 4 5 1 2或5 1 2 3 4等等。有什么 算法 吗? 编辑: 我想以循环方式打印所有组合。我不想在初始阶段说明起点。 问题答案: (如果要从向下迭代数组,请在数组下标表达式中更改为。) 我应该注意,就执行速度而言,这可能不是表达循环的最有效方法。但是,差异很小,并且 很可能无关紧

  • 我有很多用Java编写的cucumber .feature文件。 看起来它们是并行运行的。 我如何以单线程的方式一个接一个地运行cucumber测试? 运行测试配置为:

  • 我想以多线程方式阅读10个邮件帐户的未读邮件。 但是如果线程池大小为5,那么将使用线程池中的5个线程。每个线程将读取一个邮件帐户。因此,一旦Thread_1读取了第一个邮箱,它应该会读取mailbox_6。那么线程2将读取mailbox_7。 当所有邮件帐户都被读取一次后,循环将从第一个邮件帐户开始。 我们如何在java中做到这一点?

  • systemd 方式 在 terminal 中执行以下命令: sudo vim /etc/systemd/system/gitea.service 接着拷贝示例代码 gitea.service 并取消对任何需要运行在主机上的服务部分的注释,譬如 MySQL。 修改 user,home 目录以及其他必须的初始化参数,如果使用自定义端口,则需修改 PORT 参数,反之如果使用默认端口则需删除 -p

  • 问题内容: 问题很容易,我想遍历列表的每个元素和成对的下一个(将最后一个与第一个包裹在一起)。 我考虑过两种非Python的方法: 和: 预期输出: 关于这样做的更pythonic方式的任何建议?也许有一个我没有听说过的预定义功能? 同样,更一般的n折(三重奏,四重奏等代替对子)也可能很有趣。 问题答案: 我已经编写了元组通用版本的代码,我喜欢第一个版本,因为它非常简洁,我看的越多,对我的感觉就越