Runnable和Callable

Runnable和Callable都可以在主线程之外单独启一个线程。

Runnable和Callable的区别在于:

使用方式:Runnable可直接使用  new Thread(Runnable runnable).start();来启动一个线程

Callable需要使用FutureTask进行封装,使用new Thread(new FutureTask<>(Callable  callable)).start();来启动一个线程

返回值:Runnable只是单纯的启动一个线程任务,这个线程任务(run方法)不能返回结果给主线程

Callable在启一个线程任务的同时可以通过Future对线程(call方法)的运行结果进行返回

异常处理:Runnable不支持抛出异常,所有异常只能在run方法内消化。

Callable支持异常抛出,可以将call方法内部的异常抛出。指定注意的是抛出的异常并不是抛到.start()方法上去了,而是抛到用来获得返回结果的FutureTask.get()方法上。

阻塞:Runnable不会阻塞主线程的运行。

Callable分两种情况。一种是不获得call方法返回结果即不调用FutureTask.get()的情况,此情况下在阻塞问题上与Runnable无明显区别。另一种情况是需要获得call方法返回结果即调用FutureTask.get()方法的情况,此种情形下如果再运行FutureTask.get()方法时对应的Callable线程还未执行完毕,那么主线程将会被阻塞,直到Callable线程的call方法执行完毕并将结果返回给主线程之后,主线程才会继续执行,因此此种情形下一般使用线程控制类CountDownLatch来控制线程来避免主线程因为一些问题被长时间阻塞。

下面通过一小段代码来验证以上结论:

package sync;


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


public class RunnableAndCallableTest {


    public static void main(String[] args) {
        long t1 = System.currentTimeMillis();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("This Is Runnable");
            }
        };


        new Thread(runnable).start();  // 
        long t2 = System.currentTimeMillis();
        // 以上代码明显不会运行1s,因此若是运行超过1s则可值阻塞了主线程
        System.out.println("runnable是否阻塞主线程:" + String.valueOf((t2 - t1) > 1000));
        
        Callable<String> c = new Callable<String>() {
            
            @Override
            public String call() throws Exception {
                Thread.sleep(1000);
                System.out.println("This Is Callable");
                return "The ruturn of Callable";
            }
        };
        
        Callable<String> c2 = new Callable<String>() {
            
            @Override
            public String call() throws Exception {
                int i = 0;
                i= 1/i; // 异常向外抛出
                return "The return of Exception Callable";
            }
        };
        // 对Callable进行封装
        FutureTask<String> task = new FutureTask<>(c);
        FutureTask<String> task2 = new FutureTask<>(c2);
        long t3 = System.currentTimeMillis();
        // 启动线程
        try {
            new Thread(task).start(); 
            new Thread(task2).start();
            System.out.println("异常未抛到start方法上");
        } catch (Exception e) {
            System.out.println("异常抛到了start方法上");
        }
        long t4 = System.currentTimeMillis();
        // 大于1s的话可以认为主线程阻塞到start方法上了
        System.out.println("主线程阻塞在start方法上:" + String.valueOf(t4 - t3 > 1000));
        
        try {
            System.out.println(task.get());
            System.out.println(task2.get());
            System.out.println("异常未抛到了get方法上");
        } catch (Exception e) {
            System.out.println("异常抛到了get方法上");
        }
        long t5 = System.currentTimeMillis();
        // 大于1s的话可以认为主线程阻塞到get方法上了
        System.out.println("主线程阻塞在get方法上:" + String.valueOf(t5 - t4 > 1000));
    }
}

执行结果:

runnable是否阻塞主线程:false
异常未抛到start方法上
主线程阻塞在start方法上:false
This Is Runnable
This Is Callable
The ruturn of Callable
异常抛到了get方法上
主线程阻塞在get方法上:true

参考:

说说Runnable与Callable

Java线程(七):Callable和Future

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yue_hu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值