java中runnable和callable的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中runnable和callable的区别相关的知识,希望对你有一定的参考价值。

1、意义区别:

Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;

Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。

2、使用方法区别:

定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。

举例说明:

package org.thread.demo;

class MyThread extends Thread

private String name;

public MyThread(String name)

super();

this.name = name;

public void run()

for(int i=0;i<10;i++)

System.out.println("线程开始:"+this.name+",i="+i);

参考技术A Runnable和Callable的区别是,
(1)Callable规定的方法是call(),Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
(3)call方法可以抛出异常,run方法不可以

(4)运行Callable任务可以拿到一个Future对象,Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如果线程没有执行完,Future.get()方法可能会阻塞当前线程的执行;如果线程出现异常,Future.get()会throws InterruptedException或者ExecutionException;如果线程已经取消,会跑出CancellationException。取消由cancel 方法来执行。isDone确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明Future<?> 形式类型、并返回 null 作为底层任务的结果。Future接口的定义如下:

Future模式
Future模式在请求发生时,会先产生一个Future凭证给发出请求的客户,它的作用就像是Proxy物件,同时,由一个新的执行线程持续进行目标物件的生成(Thread-Per-Message),真正的目标物件生成之后,将之设定至Future之中,而当客户端真正需要目标物件时,目标物件也已经准备好,可以让客户提取使用。
结合JDK的Future来看,就是你run线程后,你可以把线程的返回值赋给Future并返回一个Future对象。这时你可以立即拿到这个对象,然后进行下面的逻辑。但是如果你要get这个Future中的线程结果,就会被阻塞直到线程结束。
就相当于现在的期房,你把手续和钱都交上去了,就可以马上拿到合同,但只有合同没有房子。这个时候你已经是有房一族了,你可以先去买家电买装修(走下面的其他逻辑)。但是你要把家电和装修放进去,就必须等到房子完工(阻塞)。

public interface Future<T>

V get() throws ...;
V get(long timeout, TimeUnit unit) throws ...;
void cancle(boolean mayInterrupt);
boolean isCancelled();
boolean isDone();

具体的实现类为java.util.concurrent.FutureTask<V>。

1、通过实现Callable接口来创建Thread线程:

其中,Callable接口(也只有一个方法)定义如下:

public interface Callable<V>

V call() throws Exception;

步骤1:创建实现Callable接口的类SomeCallable<Integer>;

步骤2:创建一个类对象:

Callable<Integer> oneCallable = new SomeCallable<Integer>();

步骤3:由Callable<Integer>创建一个FutureTask<Integer>对象:

FutureTask<Integer> oneTask = new FutureTask<Integer>(oneCallable);
FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口,他的run方法中实际上会调用oneCallable.call()。

步骤4:由FutureTask<Integer>创建一个Thread对象:

Thread oneThread = new Thread(oneTask);

步骤5:启动线程:

oneThread.start();

2、通过线程池来创建线程:

步骤1:创建线程池:

ExecutorService pool = Executors.newCachedThreadPool();

步骤2:通过Runnable对象或Callable对象将任务提交给ExecutorService对象:

Future<Integer> submit(Callable<Integer> task);

网上的例子

[java] view plain copy print?
import java.util.concurrent.*;

public class Test

public static void main(String[] args) throws InterruptedException,
ExecutionException
final ExecutorService exec = Executors.newFixedThreadPool(5);
Callable<String> call = new Callable<String>()
public String call() throws Exception
Thread.sleep(1000 * 10);//休眠指定的时间,此处表示该操作比较耗时
return "Other less important but longtime things.";

;
Future<String> task = exec.submit(call);
//重要的事情
System.out.println("Let's do important things. start");
Thread.sleep(1000 * 3);
System.out.println("Let's do important things. end");

//不重要的事情
while(! task.isDone())
System.out.println("still waiting....");
Thread.sleep(1000 * 1);

System.out.println("get sth....");
String obj = task.get();
System.out.println(obj);
//关闭线程池
exec.shutdown();



输出结果:

Let's do important things. start
Let's do important things. end
still waiting....
still waiting....
still waiting....
still waiting....
still waiting....
still waiting....
still waiting....
get sth....
Other less important but longtime things.
参考技术B Runnable和Callable的区别是,
(1)Callable规定的方法是call(),Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
(3)call方法可以抛出异常,run方法不可以

(4)运行Callable任务可以拿到一个Future对象,Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如果线程没有执行完,Future.get()方法可能会阻塞当前线程的执行;如果线程出现异常,Future.get()会throws InterruptedException或者ExecutionException;如果线程已经取消,会跑出CancellationException。取消由cancel 方法来执行。isDone确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明Future<?> 形式类型、并返回 null 作为底层任务的结果。

Java Runnable与Callable区别

接口定义

Callable接口

public interface Callable<V> {
    V call() throws Exception;
}

Runnable接口

public interface Runnable {
    public abstract void run();
}

相同点

  • 都是接口

  • 都可以编写多线程程序

  • 都采用Thread.start()启动线程

不同点

  • Runnable没有返回值;Callable可以返回执行结果,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果

  • Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛

注:Callalbe接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。

示例

callable-1

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

public class CallableAndFuture {
    public static void main(String[] args) {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(6000);
                return new Random().nextInt();
            }
        };
        FutureTask<Integer> future = new FutureTask<>(callable);
        new Thread(future).start();
        try {
            Thread.sleep(1000);
            System.out.println("hello begin");
            System.out.println(future.isDone());
            System.out.println(future.get());
            System.out.println(future.isDone());
            System.out.println("hello end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

callable-2

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

public class CallableThreadTest implements Callable<Integer> {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CallableThreadTest ctt = new CallableThreadTest();
        FutureTask<Integer> ft = new FutureTask<>(ctt);
        new Thread(ft, "有返回值的线程").start();
        System.out.println("子线程的返回值" + ft.get());
    }

    @Override
    public Integer call() {
        int i;
        for (i = 0; i < 10; i += 2) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
        return i;
    }
}

优势

多线程返回执行结果是很有用的一个特性,因为多线程相比单线程更难、更复杂的一个重要原因就是因为多线程充满着未知性,某条线程是否执行了?某条线程执行了多久?某条线程执行的时候我们期望的数据是否已经赋值完毕?无法得知,我们能做的只是等待这条多线程的任务执行完毕而已。而Callable+Future/FutureTask却可以获取多线程运行的结果,可以在等待时间太长没获取到需要的数据的情况下取消该线程的任务,真的是非常有用。

public class CallableAndFuture {
    public static void main(String[] args) {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(6000);
                return new Random().nextInt();
            }
        };
        FutureTask<Integer> future = new FutureTask<>(callable);
        new Thread(future).start();
        try {
            Thread.sleep(1000);
            System.out.println("hello begin");
            System.out.println(future.isDone());
//            future.cancel(false);
            if (!future.isCancelled()) {
                System.out.println(future.get());
                System.out.println(future.isDone());
                System.out.println("hello end");
            } else {
                System.out.println("cancel~");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

以上是关于java中runnable和callable的区别的主要内容,如果未能解决你的问题,请参考以下文章

java中runnable和callable的区别

Java并发多线程编程——Callable和Runnable接口的区别

Java Runnable与Callable区别

Callable, Runnable, Future, FutureTask

Java多线程Runnable与Callable区别与拓展

Java Callable,Runnable比较及用法