实现多线程的四种方式
继承 Thread 类,重写 run 方法
public class TestExtendsThread extends Thread {
public static void main(String[] args) {
TestExtendsThread thread1 = new TestExtendsThread();
thread1.start();
}
@Override
public void run() {
System.out.println("继承了 Thread 类");
}
}
实现 Runnable 接口,实现 run 方法
public class TestImplRunnable implements Runnable {
public static void main(String[] args) {
TestImplRunnable runnable = new TestImplRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
@Override
public void run() {
System.out.println("实现了 Runnable 接口");
}
}
Callable 和 FutureTask
public class TestImplCallable implements Callable<String> {
public static void main(String[] args) {
TestImplCallable callable = new TestImplCallable();
FutureTask<String> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
}
@Override
public String call() throws Exception {
System.out.println("Callable 和 FutureTask");
return null;
}
}
线程池
public class TestExecutor implements Runnable {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
TestExecutor runnable = new TestExecutor();
executor.execute(runnable);
executor.shutdown();
}
@Override
public void run() {
System.out.println("线程池");
}
}
Runnable 和 Callable 的区别
首先来看看 Runnable 和 Callable 这两个接口。
// Runnable
public interface Runnable {
public abstract void run();
}
// Callable
public interface Callable<V> {
V call() throws Exception;
}
相较于 Callable
可以发现 Runnable
接口的 run
方法是没有返回值的,并且也不会抛出任何异常,由此可以得出两个关键不同点:
Callable
能返回执行结果,Runnable
是不能返回结果的。Callable
中的call
方法允许抛出异常;而Runnable
接口的run
方法的异常只能在内部消化,不能继续上抛。
获取 Callable 返回值 Demo
通过调用 FutureTask
的 get
方法,阻塞获取返回结果。
public class TestImplCallable implements Callable<String> {
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestImplCallable callable = new TestImplCallable();
FutureTask<String> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(futureTask.get());
}
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "test return value";
}
}
控制台打印结果
test return value
处理 Callable 抛出的异常 Demo
在执行过程中抛出的异常,会被包装到 ExecutionException
中,所以我们只需要从获取到原始的异常就好了。
public class TestImplCallable implements Callable<String> {
public static void main(String[] args) {
TestImplCallable callable = new TestImplCallable();
FutureTask<String> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
System.out.println(e.getCause());
}
}
@Override
public String call() throws Exception {
throw new RuntimeException("执行过程中发生异常");
}
}
控制台打印结果
java.lang.RuntimeException: 执行过程中发生异常