Java简单创建线程的三种方式

it2022-05-05  128

一 、继承Thread类创建

通过继承Thread类,重写其run方法,run()为线程要执行的任务,因此又称为执行体。创建Thread的子类的实例,创建线程对象,调用start()方法启动线程

(线程类已经继承Thread类,则无法继承其他类;每个线程都需要创建不同的Thread类,多个线程间无法共享线程类的实例变量)

public class HelloWorldThread extends Thread{ @Override public void run() { System.out.println("Hello world!"); } public static void main(String[] args) { Thread thread = new HelloWorldThread(); thread.start(); } }

二、通过实现Runnable接口创建

创建Runnable接口的实现类,重写该接口的run()方法创建Thread对象,同时创建实现类的实例作为Thread的target,调用start()方法启动线程

(Thread对象是真正的线程,实现类只是线程的执行体)

public class HelloWorldThread implements Runnable{ @Override public void run() { System.out.println("Hello world!"); } public static void main(String[] args) { Thread thread = new Thread(new HelloWorldThread()); thread.start(); } }

三、通过Callable和Future创建线程

继承Thread类和实现Runnable的方式没有返回值,也无法抛出异常,如何判断线程是否执行完成,了解任务执行情况,取消任务的执行,这就需要Callable和Future来创建线程

创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。使用FutureTask对象作为Thread对象的target创建并启动新线程。调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

Callable类似于Runnable接口的增强版,其提供的call()方法将作为线程的执行体,同时允许有返回值。但是Thread类的target参数是Runnable类型。

public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); }

这时就需要借助 Future接口,此接口可以接受call() 的返回值,RunnableFuture接口是Future接口和Runnable接口的子接口,可以作为Thread对象的target ,并且, Future 接口提供了一个实现类:FutureTask 。

public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }

FutureTask实现了RunnableFuture接口,可以作为 Thread对象的target。

public class CallableTest implements Callable<Integer> { @Override public Integer call() throws Exception { Random random = new Random(); Integer add = 0; for (int i = 0; i < 100; i++) { add = add + i; } System.out.println("CallableTest:" + add); return add; } public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<Integer> futureTask = new FutureTask<>(new CallableTest()); Thread thread = new Thread(futureTask); thread.start(); System.out.println(futureTask.get()); } }

FutureTask是一个包装器,使用FutureTask类来包装Callable对象,它通过接受Callable来创建,调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

最后我们来分析下Future接口

public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。isDone方法表示任务是否已经完成,若任务完成,则返回true。get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回。get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

最新回复(0)