Thread, Runable, Callable 还傻傻分不清?

简介: 一、Thread与Runnable1、创建线程的两种方法

在java中你怎么创建线程?相信你很快能够想到继承Thread类和实现Runnable接口这两种方式。


没错,java提供了这两种方式来创建新的线程。网上也有各种文章介绍这两种方式创建线程的区别,但是我们这里要讲的是这两种方式的关联。先分别看看这两种方式的代码


1、继承Thread类,重写run方法

image.png

  通过上面的代码我们不难发现,第一种方式中,继承了Thread类的子类通过重写父类的run方法就可以实现线程的创建。


而第二种方式中实现Runnable接口的类的对象可以作为一个参数传递到创建的thread对象中。那么Runnable为何方神圣?跟Thread类之间又有哪些不为人知的秘密?我们下期………我们下面揭晓。


2、Thread与Runnable的关联

  我们先看下Runnable的源码:

image.png

image.png

image.png

image.png

image.png

综上所述,Java线程的创建调用过程如上图所示,首先 , Java线程的start方法会创建一个本地线程(通过调用JVM_StartThread),该线程的线程函数是定义在jvm.cpp中的thread_entry,由其再进一步调用run方法。可以看到Java线程的run方法和普通方法其实没有本质区别,直接调用run方法不会报错,但是却是在当前线程执行,而不会创建一个新的线程。


二、FutureTask、Callable与Runnable

1、创建能获取结果的异步线程

上面我们了解了创建线程创建的两种方式,但是我们也能看到,通过runnable方式创建的线程无法获取返回值,如果我们需要异步执行某个操作,并且得到返回的结果,可能上面的两种创建线程的方式就不适用啦(也不是说不可以,比如通过共享变量等方式,但是使用起来会比较麻烦)!在java中提供一种比较方便的方式,那就是使用FutureTask类,我们先看看使用方式:

public class MyFutrueTask implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("我是Future模式的线程啦");
        return "Future模式的线程结束啦";
    }
    public static void main(String[] args) throws TimeoutException, ExecutionException, InterruptedException {
        FutureTask<String> futureTask = new FutureTask<String>(new MyFutrueTask());
        new Thread(futureTask).start();
        String result = futureTask.get(2000, TimeUnit.MILLISECONDS);
        System.out.println(result);
    }
}

主类实现了一个名为Callable的接口,并且实现了接口的call方法,具体的业务逻辑就在call方法中实现!实现Callable接口的类的对象可以作为一个参数传递到创建的FutureTask对象的构造函数中,而FutureTask类的对象又作为一个参数传递到Thread对象的构造函数中……


根据上面我们对Thread和Runnable的了解,能够作为参数传入到Thread构造函数的对象,一定是实现了Runnable接口的!那是不是说FutureTask对象就应该是一个Runnable的实现类呢?


2、FutureTask实现

我们先看看FutureTask类的定义

image.png

image.png

image.png

public void run() {
    ......
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                ......
            }
            if (ran)
                set(result);
        }
    } finally {
        ......
    }
}

Run方法的实现也比较简单,上述代码只保留了需要关注的代码。


在run方法中调用了构造函数传入的Callable实现类的call方法,并且用result的变量接收方法的返回值,最后调用set方法将返回结果设置到类的属性,由于FutureTask实现了Future接口,所以也就有了获取返回值以及判断线程是否运行完成、取消的能力!


也就是说,我们自定义Callable实现类的call方法,最终会在FutureTask类(也就是Runnable)的run方法中执行!而Runnable中的run方法,最终又会在Thread类的run方法中执行!!! 近期热文推荐:

目录
相关文章
面试官:除了继承Thread类和实现Runnable接口,你知道使用Callable接口的方式来创建线程吗?
面试官:除了继承Thread类和实现Runnable接口,你知道使用Callable接口的方式来创建线程吗?
130 0
面试官:除了继承Thread类和实现Runnable接口,你知道使用Callable接口的方式来创建线程吗?
创建线程的三种方式:继承Thread、Runnable 接口、Callable 接口
创建线程的三种方式:继承Thread、Runnable 接口、Callable 接口
|
Java 调度
Java多线程(Thread,Runnable,Callable)附带相关面试题
1.通过继承Thread类实现多线程,2.多线程常用操作方法,3.通过Runnable接口实现多线程,4.通过Lambda与Thread结合实现快速创建多线程,5.通过实现Callable接口得到线程返回值
446 0
面试官:除了继承Thread类和实现Runnable接口,你知道使用Callable接口的方式来创建线程吗?
对一个变量n,初始化为0,我们使用实现Runnable接口的方式创建一个线程来对其进行一次n++操作,看看能得到我们预期的结果吗?
面试官:除了继承Thread类和实现Runnable接口,你知道使用Callable接口的方式来创建线程吗?
Java——多线程高并发系列之创建多线程的四种方式(Thread、Runnable、Callable、线程池)
Java——多线程高并发系列之创建多线程的四种方式(Thread、Runnable、Callable、线程池)
Java——多线程高并发系列之创建多线程的四种方式(Thread、Runnable、Callable、线程池)
除了Thread和Runnable,你还知道第三种创建线程的方式Callable吗
相信大多数学过多线程的同学都知道创建线程常见的有三种方式,一种是继承Thread类,一种是实现Runnable接口,最后一种就是Callable,今天主要是对最后不常见的Callable方式进行介绍。
197 0
Java三种线程创建调用方式-Thread、Runnable与Callable
继承类Thread与实现接口Runnable类似,因为Thread也是实现了接口Runnable; 继承类Thread与实现接口Runnable的run方法与start方法都会调用执行体,run同步执行,start异步执行; 实现接口Callable的线程被调用时,主线程会阻塞等待执行结果; 值得注意的是:实现接口Callable的线程名称和主线程名称一样。
286 0
|
Java
Java并发编程之线程创建和启动(Thread、Runnable、Callable和Future)
这一系列的文章暂不涉及Java多线程开发中的底层原理以及JMM、JVM部分的解析(将另文总结),主要关注实际编码中Java并发编程的核心知识点和应知应会部分。 说在前面,Java并发编程的实质,是线程对象调用start方法启动多线程,而线程对象则必须是Thread类或其子类实现。
1319 0
|
Java 数据库连接 Spring
java:多线程基础之Runnable、Callable与Thread
java.lang包下有二个非常有用的东西:Runnable接口与Thread类,Thread实现了Runnable接口(可以认为Thread是Runnable的子类),利用它们可以实现最基本的多线程开发。
837 0
|
存储 Java
高并发编程之多线程锁和Callable&Future 接口
高并发编程之多线程锁和Callable&Future 接口
222 1