Java 线程创建的方法之Callable接口

本文深入探讨Java中Callable接口的使用,对比Runnable接口,介绍其在多线程环境中的优势,包括返回值、异常处理及FutureTask的运用。

Java 创建多线程的四种方式

  1. 继承 Thread 类
  2. 实现 Runnable 接口
  3. 实现 Callable 接口
  4. 利用线程池

今天咱们来重点聊聊第三种实现方式,Callable 接口。

Callable接口

Callable 接口是从 JDK1.5 以后提供的一种线程创造方法,是多线程包 java.util.concurrent 包中的,用于多线程环境。

创建线程

Callable 接口包只有一个抽象方法 call()

但是发现 Thread 类的构造方法没有可以传 Callable 接口的构造器

这就体现 Java 面向接口编程的魅力所在,在 java.util.concurrent 包下有一个 FutureTask 类,它实现了 Runnable接口,同时构造方法可以传入一个 Callable 接口。所以创建一个 Callable 线程应该这样写:

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

public class CallableDemo {
    public static void main(String[] args) {
        FutureTask futureTask = new FutureTask<Integer>(new MyThread());
        Thread thread = new Thread(futureTask,"Callable");
        thread.start();
    }


}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+" invoked");
        return 1024;
    }
}

结果

取返回值

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

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask futureTask = new FutureTask<Integer>(new MyThread());
        Thread thread = new Thread(futureTask,"Callable");
        thread.start();
        System.out.println("Callable return result: " + futureTask.get());
    }


}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+" invoked");
        return 1024;
    }
}

结果

为什么会出现Callable接口

并发、异步导致出现了 Callable 接口

Callable接口和Runnable接口的区别

  1. Callable 规定的方法是call(),而 Runnable 规定的方法是run()
  2. Callable的任务执行后可返回值,而Runnable的任务是不能返回值的
  3. call()方法可抛出异常,而run()方法是不能抛出异常的
  4. 运行Callable任务可拿到一个Future对象,获取线程的执行结果

get()方法的注意事项

Callable 实现的线程可以通过 FutureTask 的 get() 方法获取线程返回值,如果没有计算完成就要结果,会导致堵塞,计算完成会才返回值。

示例

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

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask futureTask = new FutureTask<Integer>(new MyThread());
        Thread thread = new Thread(futureTask,"Callable");
        thread.start();
        System.out.println("Callable return result: " + futureTask.get());
        System.out.println(Thread.currentThread().getName()+" Done");
    }
}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+" invoked");
        TimeUnit.SECONDS.sleep(2); //休眠2s
        return 1024;
    }
}

结果

正确的写法

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

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask futureTask = new FutureTask<Integer>(new MyThread());
        Thread thread = new Thread(futureTask,"Callable");
        thread.start();
        // 类似自旋锁
        while(!futureTask.isDone()){

        }
        System.out.println("Callable return result: " + futureTask.get());
        System.out.println(Thread.currentThread().getName()+" Done");
    }
}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+" invoked");
        TimeUnit.SECONDS.sleep(2); //休眠2s
        return 1024;
    }
}

重复任务不重复计算

示例

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

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask futureTask = new FutureTask<Integer>(new MyThread());
        //线程1
        Thread thread1 = new Thread(futureTask,"Callable 1");
        thread1.start();
        //线程2
        Thread thread2 = new Thread(futureTask,"Callable 2");
        thread2.start();
        // 类似自旋锁
        while(!futureTask.isDone()){

        }
        System.out.println("Callable return result: " + futureTask.get());
        System.out.println(Thread.currentThread().getName()+" Done");
    }
}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+" invoked");
        TimeUnit.SECONDS.sleep(2); //休眠2s
        return 1024;
    }
}

结果

观察结果可以看到只有一个线程进入了 call() 方法并返回了结果,所以对于重复的 FutureTask 任务,是不会进行重复计算的。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值