簡體   English   中英

在使用 ScheduledExecutorService 和無延遲文件讀取之間切換

[英]Switch between using ScheduledExecutorService and delay-free File Read

為了提供上下文,我使用了一個相當長的 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);
    }
}

據我所知, 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變量。 由於該變量在函數調用時被復制(按值傳遞),我們可以定義一個具有相同名稱的局部變量。 結果將是相同的,但意圖將更容易理解。

耐心等待,我們快到了。

您可以像這樣將這些函數調用包裝到 lambda 中:

    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);

還有其他幾個選項,例如用您提供給構造函數的 lambda 替換FileReaderTaskdoSomethingWithActualLine()方法。 你可以選擇任何東西——這取決於你想在這里做什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM