如何从输入流中读取一段时间?

问题描述 投票:0回答:1

我必须在特定时间从 InputStream 读取行并返回我在列表中读取的行。在我当前的解决方案中,我不确定这是否是中断线程的最佳方法,因为有时在返回后会添加一些订单,而有时则不会。

这是我当前的解决方案。

InputStream source;
ObjectMapper objectMapper;

public OrderStreamReader(InputStream source, ObjectMapper objectMapper) {
    this.source = source;
    this.objectMapper = objectMapper;
}

public List<OrderStream> get( Duration maxTime) {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    ReaderOrdersStream readerOrder = new ReaderOrdersStream();
    Future future = executor.submit(readerOrder::run);

    try {
        future.get(maxTime.toMillis(), TimeUnit.MILLISECONDS);
    } catch (TimeoutException e) {
        future.cancel(true);
    } catch (InterruptedException | ExecutionException e) {
        throw new RuntimeException(e);
    } finally {
        executor.shutdownNow();
    }

    return readerOrder.orders;
}

private class ReaderOrdersStream {
    private List<OrderStream> orders = new LinkedList<>();
    

    public void run() {
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(source))) {
            String rawOrder;
            while ((rawOrder = bufferedReader.readLine()) != null) {
                var currentOrder = objectMapper.readValue(rawOrder, OrderStream.class);
                if (Thread.interrupted()) break;
                orders.add(currentOrder);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }`

避免退货后额外加单。

java concurrency distributed-computing race-condition concurrent.futures
1个回答
0
投票

如果您在后台线程中启动任务,然后立即等待结果,则使用其他线程根本没有意义。您不妨在第一个线程中执行该任务。

顺便说一句,您没有正确处理关闭执行程序服务。请参阅 Javadoc 中

shutdownAndAwaitTermination
ExecutorService
方法中为您提供的样板代码。在Java 19+中,
ExecutorService
AutoCloseable
,所以你可以方便地使用try-with-resources语法来自动关闭执行器服务。

没有线程,只需在读取输入流时检查每个循环的经过时间。

要获取经过的时间,您可以通过调用

System.nanoTime
来计算已经过去的纳秒。但是,当读取
long
的限制时,可以重置该调用返回的不断增加的纳秒计数。达到该限制需要多长时间是未定义的,所以我不会在生产代码中依赖它。

如果微秒分辨率足够的话,获取经过时间的更好方法是使用

Instant
类及其
Instant.now()
方法来捕获当前时刻作为日期时间,偏移量为零小时-分钟-秒来自 UTC 时间子午线。使用
Duration
类来表示未附加到时间线的时间跨度。

record Person( String firstName , String lastName ) { }
ArrayList < Person > persons = new ArrayList <> ( );
Duration maxTime = Duration.ofMillis ( 10 );
InputStream inputStream = null;

Instant start = Instant.now ( );
try (
        BufferedReader bufferedReader = …
)
{
    String line;
    while ( ( line = bufferedReader.readLine ( ) ) != null )
    {
        Duration elapsed = Duration.between ( start , Instant.now ( ) );
        if ( elapsed.toNanos ( ) > maxTime.toNanos ( ) ) break;  // If we have exceeded our time limit, break out of this `while`` loop.
        String[] parts = line.split ( "," );
        String firstName = parts[ 0 ];
        String lastName = parts[ 1 ];
        Person person = new Person ( firstName , lastName );
        persons.add ( person );
    }
} catch ( IOException e )
{
    throw new RuntimeException ( e );
}
© www.soinside.com 2019 - 2024. All rights reserved.