在使用ScheduledExecutorService和无延迟文件读取之间切换

时间:2018-02-28 11:51:15

标签: java swing bufferedreader filereader scheduledexecutorservice

为了提供上下文,我正在使用一个相当长的CSV文件,其中包含一列值,提供1960 - 2016年的平均日常温度,并使用BufferedReader读取它们,如下所示:

BufferedReader br = new BufferedReader(new FileReader(new File("src/dailyTemp.csv")));

我还有一个Swing应用程序,它提供BooleanslowSpeed,用于声明是否应该运行ScheduledExecutorService。即它是否应该缓慢/快速。

此应用程序的当前用途是简单地调整是否立即返回下一个读取值或是否安排了它。

public static void main(String[] args) throws IOException
{
    startGraph(); //This is the GUI that provides the state of the slowSpeed variable

    final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    executorService.scheduleAtFixedRate(Main::readFileSlow, 0, 500, TimeUnit.MILLISECONDS);

    BufferedReader br = new BufferedReader(new FileReader(new File("src/dailyTemp.csv")));
    String newValue = "";

    while (newValue != null)
    {
        if (slowSpeed)
        {
            newValue = readFileSlow(newValue, br);
        } else
        {
            newValue = readFileFast(newValue, br);
        }
        totalCount++;
    }
    br.close();
    System.out.println("FIN");
}

public static String readFileSlow(String newValue, BufferedReader br) throws IOException
{
    while ((newValue = br.readLine()) != null)
    {
        System.out.println(newValue);
        return newValue;
    }
    return null;
}

public static String readFileFast(String newValue, BufferedReader br) throws IOException
{
    while ((newValue = br.readLine()) != null)
    {
        System.out.println(newValue);
        return newValue;
    }
    return null;
}

必要的考虑是Reader无法重新启动,因此存在while循环来检查。

我遇到的主要问题是,readFileSlow()函数无法使用变量,因此它不是Runnable且无法由ScheduledExecutorService控制。

编辑1

这是我的原始版本,合理地展示了它如何切换:

public class Main
{
    static Boolean slowSpeed = true;

    public static void main(String[] args) throws IOException, InterruptedException
    {
        startGraph();

        BufferedReader br = new BufferedReader(new FileReader(new File("src/dailyTemp.csv")));

        String newValue;

        while ((newValue = br.readLine()) != null)
        {
            if (slowSpeed)
            {
                System.out.println(newValue);
                doSomething(newValue);

                TimeUnit.MILLISECONDS.sleep(500);
            } else
            {
                System.out.println(newValue);
                doSomething(newValue);
            }
            totalCount++;
        }
        br.close();
        System.out.println("FIN");
    }

    public static void toggleSpeed(Boolean newSpeed)
    {
        slowSpeed = newSpeed;
        System.out.println(slowSpeed);
    }
}

1 个答案:

答案 0 :(得分:2)

据我所知,readFileSlowreadFileFast是完全相同的。让我们假装它不是。关键是要有两种方法可以做不同的事情。

然后,让我们稍微修复readFileSlowreadFileFast。我只显示readFileSlow,另一个看起来相同:

public static void readFileSlow(BufferedReader br) throws IOException
{
    String newValue = null;
    while ((newValue = br.readLine()) != null)
    {
        System.out.println(newValue);
        return;
    }
}

发生了什么事?

  1. 没有返回类型。如果我们想从ScheduledExecutorService调用它,那么返回的值无论如何都会丢弃。 schedule*方法不会返回Future -s来检索结果。如果是计划外阅读,即executorService.submit(),我们可以使用返回值执行某些操作。但不是现在。
  2. 没有String newValue变量。由于该变量是在函数调用(按值传递)中复制的,因此我们可以定义一个具有相同名称的局部变量。结果将是相同的,但意图将更容易理解。
  3. 忍受我,我们几乎就在那里。

    你可以将这些函数调用包装成lambdas,如下所示:

        final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    
        final BufferedReader br = new BufferedReader(new FileReader(new File("src/dailyTemp.csv")));
    
        executorService.scheduleAtFixedRate(() -> {
            try {
                readFileSlow(br);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }, 0, 500, TimeUnit.MILLISECONDS);
    

    我们需要try-catch,因为Runnable不应该抛出已检查Exception - s。 RuntimeException - s和Error - s没关系。

    您可以对实现Runnable的自定义类执行相同的操作:

    private static abstract class FileReaderTask implements Runnable {
    
        protected BufferedReader br;
    
        public FileReaderTask(BufferedReader br) {
            this.br = br;
        }
    
        protected void doSomethingWithActualLine(String line) {
            System.out.println(line);
        }
    
    }
    
    private static class SlowFileReaderTask extends FileReaderTask {
    
        public SlowFileReaderTask(BufferedReader br) {
            super(br);
        }
    
        @Override
        public void run() {
            try {
                String newValue = null;
                while ((newValue = br.readLine()) != null)
                {
                    doSomethingWithActualLine(newValue);
                    return;
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
    }
    

    然后你可以像这样安排他们:

        final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    
        final BufferedReader br = new BufferedReader(new FileReader(new File("src/dailyTemp.csv")));
    
        executorService.scheduleAtFixedRate(new SlowFileReaderTask(br), 0, 500, TimeUnit.MILLISECONDS);
    

    还有其他几个选项,例如将doSomethingWithActualLine()中的FileReaderTask方法替换为您为构造函数提供的lambda。你可以选择任何东西 - 取决于你想要做什么。