Java 创建线程三种方式

Java 创建线程三种方式

Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用三种方式来创建线程
(1)继承Thread类创建线程
(2)实现Runnable接口创建线程
(3)使用Callable和Future创建线程

1、继承Thread类创建线程

创建此类线程一般需要以下三步:
(1)定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体。

(2)创建Thread子类的实例,也就是创建了线程对象

(3)启动线程,即调用线程的start()方法

实例:

package Thread;

public class MyThread extends Thread {

    @Override
    public void run() {
        super.run();
        System.out.println("MyThread 线程启动成功!");
    }
    
    public static void main(String args[]){
        //创建线程对象
        MyThread myThread = new MyThread();   
        //启动线程
        myThread.start();
    }
}
运行结果:
MyThread 线程启动成功!

2、实现Runnable接口创建线程

一般三个步骤:
(1)定义Runnable接口的实现类,一样要重写run()方法,这个run()方法和Thread中的run()方法一样是线程的执行体

(2)创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象

(3)通过调用线程对象的start()方法来启动线程

实例:

package Thread;

//实现Runnable 接口,并重写run()方法
public class MyThread2 implements Runnable{
    @Override
    public void run() {
        System.out.println("MyThread2 线程启动成功!");
    }

    public static void main(String args[]){

        //创建线程实例
        Thread thread = new Thread(new MyThread2());
        //启动线程
        thread.start();
    }
}
运行结果:
MyThread2 线程启动成功!

3、使用Callable和Future创建线程

(1)先来了解一下Callable 接口
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其他线程执行的任务。Callable接口的定义如下:

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

Callable的类型参数是返回值的类型。例如:

Callable<Integer>表示一个最终返回Integer对象的异步计算。

(2)Future保存异步计算的结果。实际应用中可以启动一个计算,将Future对象交给某个线程,然后执行其他操作。Future对象的所有者在结果计算好之后就可以获得它。Future接口具有下面的方法:

public interface Future<V> {

   //可以用cancel方法取消该计算。如果计算还没有开始,它被取消且不再开始。
   //如果计算处于运行之中,那么如果mayInterrupt参数为true,它就被中断
    boolean cancel(boolean mayInterruptIfRunning);
    
    //判断是够被取消
    boolean isCancelled();
    
    //如果计算还在进行,isDone方法返回false;如果完成了,则返回true。
    boolean isDone();
    
    //调用被阻塞,直到计算完成
    V get() throws InterruptedException, ExecutionException;
    
    //设置等待时间,get方法的调用超时,抛出一个TimeoutException异常
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

(3) FutureTask包装器是一种非常便利的机制,同时实现了Future和Runnable接口。FutureTask有2个构造方法

public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

创建线程的步骤一般如下:
(1)创建Callable接口的实现类,并实现call()方法,然后创建该实现类的实例;

(2)使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值

(3)使用FutureTask对象作为Thread对象的target创建并启动线程(因为FutureTask实现了Runnable接口)

(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值


public class Thread3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> future = new FutureTask<Integer>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("线程启动成功!");
                return 1;
            }
        });
        new Thread(future).start();
        System.out.println("或得线程返回值为:" + future.get());
    }
}
结果:
线程启动成功!
或得线程返回值为:1

4、总结

(1)实现Runnable和实现Callable接口的方式基本相同,不过是后者执行call()方法有返回值,后者线程执行体run()方法无返回值;
(2)基于Java单继承的原因,推荐使用第二或第三种创建线程;

发布了24 篇原创文章 · 获赞 14 · 访问量 1977

猜你喜欢

转载自blog.csdn.net/qqq3117004957/article/details/104546845