Callable和Runnable接口的区别

Posted

tags:

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

参考技术A 区别1: 两者最大的区别,实现Callable接口的任务线程能返回执行结果,而实现Runnable接口的任务线程不能返回执行结果

注意点:Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞线程直到获取“将来”的结果,当不调用此方法时,主线程不会阻塞

区别2:Callable接口实现类中run()方法允许将异常向上抛出,也可以直接在内部处理(try...catch); 而Runnable接口实现类中run()方法的异常必须在内部处理掉,不能向上抛出

Demo1: Callable接口测试
package com.cc.io.currentthread;

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

public class CallableTest
public static void main(String[] args) throws ExecutionException, InterruptedException
Callable<String> callable = new CallableImpl(" my callable test");
FutureTask<String> task = new FutureTask<>(callable);



class CallableImpl implements Callable<String>



Demo2: Runnable接口测试
package com.cc.io.currentthread;

public class RunnableTest
public static void main(String[] args)
Runnable runnable = new RunnableImpl("my runnable test");
Long beginTime = System.currentTimeMillis();
new Thread(runnable).start();
Long endTime = System.currentTimeMillis();
System.out.println("cast:" + (endTime-beginTime)/1000);



class RunnableImpl implements Runnable

多线程学习记录一继承Thread类和实现Runnable接口Callable接口的区别

1)Runnable和Callable同是接口

* Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void);call方法可以抛出异常,run方法不可以
* 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。
* 加入线程池运行,Runnable使用ExecutorService的execute方法,Callable使用submit方法。

2)Thread类和Runnable接口

基于java的单继承限制,这两者第一个区别:

* 避免java单继承的局限性

* runnable接口可以自动实现资源的共享,对于Thread类,如果想要实现共享,需要将共享资源变成静态资源。这一点以卖票案例为例,如下:

继承Thread类

 1 class ExtendsThreadextends Thread{
 2         private  int ticket = 5;
 3         private String name;
 4         public FirstThread(String name){
 5             this.name = name;
 6         }
 7         public void run(){
 8             for(int i=0;i<10;i++){
 9                 if(ticket > 0){
10                     System.out.println("继承Thread-->"+name +" 卖票: "  + (ticket--));
11                 }
12             }
13         }
14     }
15 public class InitThread {
16     public static void main(String[] args) {
17                 new ExtendsThreadextends ("一号窗口").start();
18                 new ExtendsThreadextends ("二号窗口").start();
19                 new ExtendsThreadextends ("三号窗口").start(); 
20         }
21 }       
View Code

output:

    

实现Runnable接口

 1 class SecondThread implements Runnable{
 2         private  int ticket = 5;
 3         @Override
 4         public void run() {
 5             for(int i=0;i<10;i++){
 6                 if(ticket > 0){
 7                     System.out.println("实现Runnable-->"+ Thread.currentThread().getName()+" 卖票: " + (ticket--));
 8                 }
 9             }
10         }
11         
12     }
13 
14 public static void main(String[] args) {
15                 SecondThread secondThread = new SecondThread();
16         new Thread(secondThread,"一号窗口").start();
17         new Thread(secondThread,"二号窗口").start();
18         new Thread(secondThread,"三号窗口").start();
19 
20 }    
View Code

output:

   

 1.以上第一种new 了3个Thread 对象,可以看到相当于三个独立的线程在执行卖票任务;第二种也是new了3个对象,但是只有一个Runnable对象,3个Thread共享这个Runnable对象的代码,因此出现了三个线程共同执行卖票任务的结果。如果new出3个Runnable对象执行的话,也会出现3个线程独自各卖5张票。

 2.第二种就达到了资源共享的目的,如果想要第一种也实现第二种的效果的话,把ticket变量改成static即可,所以说资源共享是相对的。

 3.资源共享就设计到线程安全问题,ticket--操作并不具有原子性。ticket有可能输出负数,在System.out...前面加上线程休眠操作,会出现以下结果:

   

当ticket=1的时候,窗口一执行到ticket>0,窗口二执行到ticket--,此时ticket已经是0了,但是窗口三、一线程还是会继续执行ticket--操作,导致输出ticket为0,甚至为负数。
要解决这个问题,需要引入线程的同步操作即互斥锁。

 

以上是关于Callable和Runnable接口的区别的主要内容,如果未能解决你的问题,请参考以下文章

runnable 和 callable 有什么区别

java中runnable和callable的区别

面试题之Runnable和Callable的区别

Runnable接口和Callable接口的区别。

callable和runnable的区别

callable和runnable的区别