详述Java实现Callable接口实现多线程的方式

公司项目忙的晕头转向,终于有时间可以看点自己想看的东西了。在这里把最近学习的实现Callable接口实现多线程的方式做一个总结:

首先我们都知道,在Java中最常见的是继承Thread类和实现Runnable接口来实现多线程(

这里我推荐采用实现接口的方式来实现多线程,原因有两点:

1、Java的设计是单继承的设计,如果采用继承Thread的方式实现多线程,则不能继承其他的类。

2、采用接口能够更好的实现数据共享。线程的启动需要Thread类的start方法,如果采用继承的方式每次新建一个线程时,每个新建线程的数据都会单独的存在线程内存中,这样每个线程会单独的操作自己线程的数据,不能更好的实现线程之间的数据共享)

但是无论以上哪种方式实现多线程,都存在一个问题,就是线程run方法没有返回值,如果一个线程需要有返回值时,可以采用本章讲的实现Callable接口来实现多线程

首先看一下Callable接口的源码

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

首先明确一点这是一个函数式接口,其中的@FunctionalInterface定义了这个接口为函数式接口(具体函数式接口和普通接口有何区别可以自行查阅相关资料) ,Callable接口接受一个泛型作为接口中call方法的返回值类型,因此我们在使用时需要传入一个返回值类型。

然后我去实现这个接口来定义我自己的线程类,这里我传入了一个String类型作为接口call方法的返回值类型,然后实现了call方法,将result作为返回结果返回

public class MyCallable<String> implements Callable<String> {

	private int tickt=10;
	
	@Override
	public String call() throws Exception {
		// TODO Auto-generated method stub
		String result;
		while(tickt>0) {
			System.out.println("票还剩余:"+tickt);
			tickt--;
		}
		result=(String) "票已卖光";
		return result;
	}

}

采用实现Callable接口实现多线程启动方式和以往两种的方式不太一样,下面就看一下怎样启动采用实现Callable接口的线程,首先我 new 一个我的实现实例,然后将我生成的实例对象注册进入到

FutureTask类中,然后将FutureTask类的实例注册进入Thread中运行。最后可以采用FutureTask<V>中的get方法获取自定义线程的返回值

	public static void main(String[] args) throws InterruptedException, ExecutionException {		
		MyCallable<String> mc=new MyCallable<String>();
		FutureTask<String> ft=new FutureTask<String>(mc);
		new Thread(ft).start();
		String result=ft.get();
		System.out.println(result);
	}
	

最后我解释一下为什么实现Callable接口实现的多线程的形式需要采用这样的方式去启动线程。上面我们已经看了Callable接口的源码,其中只有一个call方法的定义,下面我们看一下FutureTask<V>类的定义,其中我们可以看到FutureTask<V>类是实现了RunnableFuture<V>接口的,我们再看FutureTask<V>类其中 的一个构造方法如下,其中需要传入一个Callable<V>类型的参数,更多内容可以自行查看FutureTask<V>类的具体实现,这里我们只需要知道此构造方法传入一个Callable<V>类型的参数,然后赋值给FutureTask<V>中的私有属性

public class FutureTask<V> implements RunnableFuture<V>{ 


 public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
}

然后我们再看 RunnableFuture<V>  接口,这个接口我们可以看到继承了Runnable, Future<V> 两个接口

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

最后就是我们Thread类,无论我们以怎样的形式实现多线程,都需要调用Thread类中的start方法去向操作系统请求io,cup等资源,在Tread中有一个构造方法是传入一个Runnable接口类型的参数,而我们上面的FutureTask<V>实例实现了 RunnableFuture<V> 接口,而 RunnableFuture<V> 接口又继承了Runnable接口和 Funture<V>接口,因此我们可以将FutureTask<V> 的一个实例当做是一个Runnable接口的实例传入Thread来启动我们新建的线程

下面是我画的各个类之间的关系图

 

  • 34
    点赞
  • 147
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值