Java创建并执行线程的四种方法

java里面创建线程有四种方式:
无返回:

  1. 实现Runnable接口,重写run();
  2. 继承Thread类,重写run();
    有返回:
  3. 实现Callable接口,重写call(),利用FutureTask包装Callable,并作为task传入Thread构造函数;
  4. 利用线程池;

下面来看看具体的创建方式:

5. 继承Thread类,重写run();

创建:创建线程只需要继承Thread类,然后在run方法里写下线程要实现的任务即可;

java创建一个线程打印a java创建一个线程的方法_java


调用:通过调用start方法来启动线程而不能直接调用run方法。

java创建一个线程打印a java创建一个线程的方法_java_02

① Thread类本质上是实现了Runnable接口,Thread对象代表一个线程的实例。

② Runnable接口只有一个抽象的run()方法。

③ 启动线程的唯一方法就是通过Thread类的start()实例方法。

④ start()方法是一个native方法,它将启动一个新线程,并执行run()方法。

⑤ 自定义类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。

6. 创建任务,实现Runnable接口,重写run()。(受欢迎)

因为Java只能单继承,继承了Thread类就不能再继承别的类了所以实现继承更推崇的是让线程类实现Runnable接口。

java创建一个线程打印a java创建一个线程的方法_java创建一个线程打印a_03


将Runnbale作为参数传入Thread的构造函数,创建Thread.

java创建一个线程打印a java创建一个线程的方法_java_04


3. Callable接口只包含抽象方法V call()。

java创建一个线程打印a java创建一个线程的方法_返回结果_05


利用Callable接口创建并启动新线程的步骤:

① 定义MyClass实现Callable接口;Class MyClass implements Callable

② 重写call(),将执行的代码写入;

③ 创建FutureTask的对象;FutureTask中定义了run(),run()内部调用了call(),并保存了call()的返回值;FutureTask futuretask = new FutureTask(newMyClass());

④ 创建Thread的对象;Thread thread = new Thread(futuretask);//传入参数Runnable接口

⑤ 启动线程;thread.start();[图片]

⑥ 可通过FutureTask类的get()方法获得线程执行结束后的返回值,即call的返回值。futuretask.get();

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MyThread {

    public static void main(String[] args) throws InterruptedException {
        FutureTask<Integer> task = new FutureTask<Integer>(new CallableImpl());
        Thread thread = new Thread(task);
        thread.start();
        try {
            System.out.println("task.get() returns " + task.get());
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class CallableImpl implements Callable<Integer> {

    private static Integer value = 0;

    @Override
    public Integer call() throws Exception {
        System.out.println("执行call方法之前 value = " + value);
        value = value.intValue() + 1;
        System.out.println("执行call方法之后 value = " + value);
        return value;
    }
}

运行结果:
执行call方法之前 value = 0
执行call方法之后 value = 1
task.get() returns 1
4. 通过线程池来创建线程
① new ThreadPoolExecutor(…);
② 创建任务Task implements Callable,重写run()方法;
③ 通过线程池的execute()或submit()将任务command传入线程池;
④ 获取返回值:

  1. 实现Callable接口,重写call()方法
    class CallableImpl implements Callable
  2. 定义线程池
    ThreadPoolExecutor executor
  3. 利用submit()方法提交任务
    Future<?> future = executor.submit(new CallableImpl());
  4. 利用FutureTask类get()方法获取返回值
    res = task.get();
    这里future申明为Future对象,但是它是由FutureTask实现的,也可以直接申明为FutureTask future:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadPool {
    public static void main(String[] args) throws InterruptedException, ExecutionException {

        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(20));
        Future task;
        for (int i = 0; i < 5; i++) {
            task = executor.submit(new CallableImpl());
            System.out.println("线程返回结果:" + task.get());
        }
        executor.shutdown();
    }
}

class RunnableImpl implements Runnable {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        System.out.println("hhh");
        System.out.println(Thread.currentThread().getName());
    }
}

运行结果:

执行call方法之前 value = 0
 执行call方法之后 value = 1
 线程返回结果:1
 执行call方法之前 value = 1
 执行call方法之后 value = 2
 线程返回结果:2
 执行call方法之前 value = 2
 执行call方法之后 value = 3
 线程返回结果:3
 执行call方法之前 value = 3
 执行call方法之后 value = 4
 线程返回结果:4
 执行call方法之前 value = 4
 执行call方法之后 value = 5
 线程返回结果:5

总结:
线程的创建有四种方式:主要分为有返回和无返回,具体根据使用场景来选择。

  1. 如果不需要返回且线程数量小,则建议采用实现Runnable接口,重写run()的方式;
  2. 如果需要返回且线程数量小,则建议采用实现Callable接口,重写call(),利用FutureTask包装成一个Runnable,再作为参数传入Thread的构造方法的方式创建线程;
  3. 如果线程数量较多,则建议采用线程池方式创建:execute提交任务实现无返回操作,submit提交任务实现有返回操作。

补充:FutureTask
JDK1.8中FutureTask实现了RunnableFuture,而RunnableFuture顾名思义就是Runnable接口和Future接口的结合体。因此,FutureTask对象可以作为Runnable对象来用,比如

Thread thread = new Thread(new FutureTask<V>());

也可以作为Future来用。这就是Java的有魅力的地方。。。

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