在线OJ(一)
目标:仿照牛客/leetcode这类在线OJ网站,实现在线做题/判题功能
核心功能
- 题目列表页,展示当前系统中所有的题目。
- 题目详情页,显示题目的具体要求和代码模板,提供一个编辑框供用户来编辑代码。
- 代码的编译/运行/测试功能,能够针对用户提交的代码,进行编译运行,并自动执行测试用例,返回测试结果。
编译模块:给定一个java代码文件(只考虑单个文件的情况,不考虑多文件复杂工程)能够通过代码来控制jdk进行编译运行。通过借助Runtime这个对象,可以创建出一个子进程,并且让子进程来执行一个相关的命令。编译:javac,运行:java
进程与线程
进程是资源分配的基本单位。
线程是CPU调度和执行的基本单位
线程相比于进程的优势:
1.线程更轻量,创建一个线程开销比创建进程低很多;销毁一个线程的开销也比销毁一个进程开销低很多。
2.同一个进程中的所有线程共享着一些数据。
线程相比于进程的劣势:
1.线程代码编写更困难,涉及线程安全。
2.线程代码调试也更加困难。
3.对于程序的稳定性也就提出了更高要求。
CommandUtil
如何利用子进程来执行命令?接下来就是对CommandUtil的讲解,其本质就是利用了jdk的Runtime对象。
exec方法干了两件事:1.创建子进程。2.进程程序替换
这里的运行结果实际上是父进程的输出结果,那么如果我们想要获取子进程的输出结果就需要使用到“重定向”功能,把进程输出的内容写到指定的文件中。具体实现:实现重定向,需要先获取到子进程对象,借助exec返回的Process对象,通过标准输入输出来重定向保存子进程输出结果。
执行结果发现:文件是有了,但是内容没有,为什么?因为一个命令的输出内容也可能是通过标准错误来打印的。操作系统中的任何一个进程,启动的时候都会自动打开三个文件:标准输入、标准输出、标准错误。并通过文件管理的方式,将其组织起来。我们只需要将上图第三步复制,修改为标准错误重定向就好了(process.getErrStream())。
执行结果:
首先,生成了两个对应的文件。
第二,在stderrFile.txt文件中可以看到内容,也就是我们在cmd中直接输入javac的内容。
当然,我们还需要考虑一件事,本身预期目标是用父进程中的run方法来控制子进程执行功能。在执行run的过程中,子进程也在执行。当run执行结束之后,也必须确保子进程也已经执行完了。但是此时这个代码中,子进程和父进程之间是并发关系,谁先执行完时无法确定的,为了能够明确让子进程先执行完,就需要让父进程进行等待。
CommandUtil代码
import java.io.*;
// 借助这个类,让java代码能够去执行一个具体的指令
// 例如:javac Test.java
public class CommandUtil {
//cmd 表示要执行的命令
//stdoutFile 表示标准输出结果重定向到哪个文件中,如果为null表示不需要重定向
//stderrFile 表示标准错误结果重定向到哪个文件中。
public static int run(String cmd,String stdoutFile,String stderrFile) throws IOException, InterruptedException {
//1.获取Runtime对象 ,Runtime对象是一个单例的
Runtime runtime = Runtime.getRuntime();
//2.通过runtime对象中的exec方法来执行一个指令。
// 相当于在命令行中输入了命令
// 获取exec返回的Process对象
Process process = runtime.exec(cmd);
//3.通过标准输入输出对输出结果进行重定向保存
if(stdoutFile != null){
//进程的标准输出中的结果就可以通过这个InputStream来获取
InputStream stdoutFrom = process.getInputStream();
OutputStream stdoutTo = new FileOutputStream(stdoutFile);
int ch = -1;
while((ch = stdoutFrom.read()) != -1){
stdoutTo.write(ch);
}
stdoutFrom.close();
stdoutTo.close();
}
//4.针对标准错误也进行重定向
if(stderrFile != null){
InputStream stderrFrom = process.getErrorStream();
OutputStream stderrTo = new FileOutputStream(stderrFile);
int ch = -