Java 常用API编程

Java调用shell并打印输出结果


import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
        Process proc = Runtime.getRuntime().exec("pwd");
        InputStream inputStream = proc.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line = null;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        proc.waitFor();
    }
}

多线程 

多线程部分,方便查找,就不拆分到其他篇了。

实现多线程的方式包括继承Thread,实现Runnable或Callable接口,前两者是没有返回体的(Callable的V即为我们返回体的数据类型),本篇不对前两种方式进行讲解,仅介绍Callable。

FutureTask获取子线程返回值

FutureTask适合开启单个子线程并在主线程中监控、阻塞获取子线程的返回值,由于其get()方法有阻塞,如果需要获取多个子线程的返回结果,主线程中需要等子线程挨个执行完(因为需要挨个获取执行结果),达不到好的多线程效果,以下是示例:

  • 先编写子线程类(不带任何逻辑,打印-睡3秒-返回结束语句):
import java.util.concurrent.Callable;
public class UglyRunner implements Callable {
    @Override
    public String call() throws Exception {
        String threadName = Thread.currentThread().getName();
        System.out.println(String.format("%s start to run: %s", threadName, new Date()));
        System.out.println(threadName + ": Please hold on, I'm running....");
        Thread.sleep(3000);
        System.out.println(String.format("%s stop running: %s", threadName, new Date()));

        return threadName + ": I'm out now";
    }
}
  • 再编写主类(循环检查子线程执行是否完成,子线程执行完成后获取其返回值并打印):
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class WaitSubRes {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask futureTask = new FutureTask<>(new UglyRunner());
        Thread thread = new Thread(futureTask);
        thread.start();
        // 每1秒循环检查一次子线程是否完成执行
        while (!futureTask.isDone()) {
            System.out.println(Thread.currentThread().getName() + ": the sub task is still running....");
            Thread.sleep(1000);
        }
        System.out.println(futureTask.get());
    }
}

以上代码,主线程循环检查了子线程的运行状态,并在子线程运行完毕后打印了子线程的返回值。接下来,尝试在启动主类中创建多个子线程。

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

public class WaitMultiSubRes {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(3);

        UglyRunner uglyRunner = new UglyRunner();
        for (int i = 0; i < 3; i++) {
            FutureTask futureTask = new FutureTask<>(uglyRunner);
            executor.submit(futureTask);
            while (!futureTask.isDone()) {
                System.out.println(Thread.currentThread().getName() + ": the sub task is still running....");
                Thread.sleep(1000);
            }
            System.out.println(futureTask.get());
        }
        executor.shutdown();
    }
}

这里用了线程池的写法,不过无关大局。通过观察打印输出结果,可以发现三个子线程是顺序执行的(红线框为开始时间,绿线框为结束时间):

Java 常用API编程_第1张图片

实际开发中,我们肯定不喜欢这样的结果,阻塞影响了多线程只能逐个进行,需要换一种方法,下面介绍。

ExecutorCompletionService获取多个子线程返回值

ExecutorCompletionService提供的take()方法可以阻塞获取子线程返回值,批量任务的返回值只需调用同样次数的take()即可,先完成运行的子线程返回值先被获取到。以下为相关代码:

import java.util.concurrent.*;


public class WaitMultiSubRes2 {
    public static int nThreads = 3;

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        UglyRunner uglyRunner = new UglyRunner();
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletionService completionService = new ExecutorCompletionService<>(executorService);

        for (int i = 0; i < nThreads; i++) {
            completionService.submit(uglyRunner);
        }
        String result = "";
        for (int i = 0; i < nThreads; i++) {
            result = String.format("%s %s", result, completionService.take().get());
        }
        System.out.println(result);
        executorService.shutdown();

    }
}

运行结果:

Java 常用API编程_第2张图片

可以看到,3个子线程在同一时间并行启动,而不是FutureTask那样串行启动。

你可能感兴趣的:(Java,java)