设置用Java读取的阻塞文件

Bee*_*ope 7 java testing io mkfifo

我想设置一个用Java读取的阻塞文件.也就是说,有一个文件,当包装FileInputStream和任何read()方法被调用时,调用块.

我想不出一个简单的与操作系统无关的方法 - 在类Unix操作系统上,我可以尝试使用mkfifo该文件创建FIFO 并从中读取.一个可能的解决方法是创建一个非常大的文件并从中读取 - 在捕获堆栈之前读取不太可能完成,但是它很丑陋而且很慢(实际上读取在缓存时仍然非常快).

相应的套接字read()案例很容易设置 - 自己创建一个套接字并从中读取,你可以有确定性的阻塞.

目的是检查方法的堆栈以确定在这种情况下顶框架是什么.想象一下,我有一个组件定期对所有正在运行的线程的堆栈跟踪进行采样,然后尝试对该线程当前正在执行的操作进行分类.它可以做的一件事是文件IO.所以我需要知道文件IO期间"堆栈顶部"是什么样的.我已经通过实验确定了(只是以各种方式读取文件并对堆栈进行采样),但我想编写一个如果这种情况发生变化就会失败的测试.

编写这样一个测试的自然方法是启动一个执行文件读取的线程,然后检查顶部框架.为了可靠地执行此操作,我想要一个阻塞读取(否则线程可能会在执行堆栈跟踪之前完成其读取等).

apa*_*gin 5

要获得有保证的阻止I/O,请从控制台读取,例如/dev/console在Linux或CONWindows上.

为了使这个平台无关的,你可以破解FileDescriptorFileInputStream:

    // Open a dummy FileInputStream
    File f = File.createTempFile("dummy", ".tmp");
    f.deleteOnExit();
    FileInputStream fis = new FileInputStream(f);

    // Replace FileInputStream's descriptor with stdin
    Field fd = FileInputStream.class.getDeclaredField("fd");
    fd.setAccessible(true);
    fd.set(fis, FileDescriptor.in);

    System.out.println("Reading...");
    fis.read();
    System.out.println("Complete");
Run Code Online (Sandbox Code Playgroud)

UPDATE

我意识到你甚至不需要一种方法来阻止.为了获得正确的堆栈跟踪,您可以read()在无效的FileInputStream上调用:

    FileInputStream fis = new FileInputStream(new FileDescriptor());
    fis.read(); // This will throw IOException exactly with the right stacktrace
Run Code Online (Sandbox Code Playgroud)

如果您仍然需要阻止read(),则可以mkfifo使用命名管道:Runtime.exec在POSIX系统上运行或\\.\PIPE\MyPipeName在Windows 上创建.


OfN*_*ing 1

我不知道如何以与操作系统无关的方式创建一个在读取时始终会阻塞的文件。

如果我试图在调用特定函数时查找堆栈跟踪,我会在调试器下运行该程序并在该函数上设置断点。尽管如此,如果时间很重要,方法断点会减慢您的程序速度,并给您带来与通常情况不同的结果。

如果您有权访问该程序的源代码,您可以制作一个假的 FileInputStream 来扩展真实的 FileInputStream 但始终会阻塞读取。您所需要做的就是在整个代码中切换掉 import 语句。然而,这不会捕获您无法切换导入语句的地方,并且如果有大量代码,这可能会很痛苦。

如果您想使用自己的 FileInputStream 而不更改程序源代码或编译,您可以制作一个自定义类加载器来加载您自定义的 FileInputStream 类,而不是真正的类加载器。您可以通过以下方式在命令行上指定要使用的类加载器:

java -Djava.system.class.loader=com.test.MyClassLoader xxx
Run Code Online (Sandbox Code Playgroud)

现在我想了想,我有一个更好的想法,不是制作一个在 read() 上阻塞的自定义 FileInputStream,而是制作一个在 read() 上打印堆栈跟踪的自定义 FileInputStream。然后,自定义类可以调用真实版本的 read()。这样您将获得所有调用的所有堆栈跟踪。