Java中Runnable和Callable的区别
在Java中,Runnable和Callable都是接口,它们都实现了java.lang.Runnable或java.util.concurrent.Callable接口,这两个接口的主要区别在于它们的返回值和异常处理方式,本文将详细介绍Runnable和Callable的区别。
1、返回值
Runnable接口只有一个run()方法,该方法没有返回值,而Callable接口则有两个方法:call()和get(),其中call()方法没有返回值,get()方法用于获取call()方法的返回值。
2、异常处理
Runnable接口的run()方法不能抛出受检异常(checked exception),只能抛出未检查异常(unchecked exception),而Callable接口的call()方法可以抛出受检异常,并可以通过get()方法获取到对应的异常对象。
3、使用场景
由于Runnable接口不能抛出受检异常,因此它通常用于实现不需要返回值的任务,例如线程的启动、线程池中的任务等,而Callable接口可以抛出受检异常,因此它通常用于实现需要返回值的任务,例如多线程编程中的计算任务等。
下面通过一个简单的示例来说明Runnable和Callable的使用区别:
import java.util.concurrent.*; public class RunnableAndCallableDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); // 使用Runnable实现不需要返回值的任务 Runnable runnableTask = new Runnable() { @Override public void run() { System.out.println("Runnable任务开始执行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Runnable任务执行结束"); } }; executorService.execute(runnableTask); // 使用Callable实现需要返回值的任务 Callable<Integer> callableTask = new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println("Callable任务开始执行"); Thread.sleep(2000); return 42; } }; Future<Integer> future = executorService.submit(callableTask); try { System.out.println("Callable任务返回值:" + future.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } finally { executorService.shutdown(); } } }
相关问题与解答
1、如何自定义一个实现Runnable接口的类?
要自定义一个实现Runnable接口的类,只需创建一个类,然后重写run()方法即可。
public class MyRunnable implements Runnable { @Override public void run() { System.out.println("MyRunnable任务开始执行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("MyRunnable任务执行结束"); } }
2、如何自定义一个实现Callable接口的类?
要自定义一个实现Callable接口的类,只需创建一个类,然后重写call()方法即可,还需要实现get()方法来获取call()方法的返回值。
import java.util.concurrent.Future; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Supplier; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; public class MyCallable implements Callable<Integer>, Supplier<Integer> { private final AtomicBoolean isDone = new AtomicBoolean(false); //标记任务是否完成的原子布尔变量,如果设置为true,那么isDone就不能再被改变了,这是因为isDone是volatile类型的,所以在多线程环境中,所有线程都能看到这个变量的变化,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个AtomicBoolean类型的变量来作为标志,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个AtomicBoolean类型的变量来作为标志,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个AtomicBoolean类型的变量来作为标志,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个AtomicBoolean类型的变量来作为标志,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个AtomicBoolean类型的变量来作为标志,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个AtomicBoolean类型的变量来作为标志,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个AtomicBoolean类型的变量来作为标志,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个AtomicBoolean类型的变量来作为标志,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个AtomicBoolean类型的变量来作为标志,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个AtomicBoolean类型的变量来作为标志,当isDone变为true后,后面的代码就不会再被执行了,因为后面的代码会认为已经完成了任务,所以这里用了一个Atomi
原创文章,作者:K-seo,如若转载,请注明出处:https://www.kdun.cn/ask/221441.html