【简述】

从java5开始,java提供了Callable接口,这个接口可以是Runnable接口的增强版,

Callable接口提供了一个call()方法作为线程执行体,call()方法比run()方法功能更强大。

【call()方法特点】

1.call()方法可以有返回值

2.call()方法可以声明抛出异常。

【Future接口】

java5提供了Future接口来代表Callable接口里的call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口,并实现了Runnable接口,所以这样可以作为Thread的target。

在Future接口里定义了一下公共方法来控制它关联的Callable任务。

1. boolean cancel( boolean mayInterruptRunning):试图取消该Future里关联的Callable任务。

2. V get() :返回Callable任务里call()方法的返回值。调用该方法会导致程序阻塞,必须等到子线程结束后才会得到返回值。

3. V get( long timeout, TimeUnit unit ):返回Callable任务里call方法的返回值。该方法然程序最多阻塞timeout和unit指定的时间,如果时间到了Callable没返回值,抛TimeoutException异常。

4.boolean isCancelled():如果Callable任务正常完成前被取消,返回true。

5.boolean isDone():如果Callable任务已完成,则返回true。

【创建和启动线程的步骤】

1.创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法没有返回值,再创建Callable实现类的实例。(从java8开始,可以直接使用Lambda表达式创建Callable对象)。

2.使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。

3.使用FutureTask作为Thread对象的target创建并启动新线程。

4.调用FutureTask对象的get方法来获得子线程执行结束后的返回值。

【示例代码】

package com.Higgin.part01;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask; class ThirdThread { } public class Demo3 { public static void main(String[] args) {
//创建Callable对象
ThirdThread rt=new ThirdThread();
//先使用Lambda表达式创建Callable<Integer>对象,
//并使用FutureTask来包装Callable对象
FutureTask<Integer> task=new FutureTask<Integer>((Callable<Integer>)()->{
int i=;
for(;i<;i++){
System.out.println(Thread.currentThread().getName()+"===="+i);
}
//call()方法可以有返回值
return
i;
}); for(int i=;i<;i++){
System.out.println(Thread.currentThread().getName()+"===="+i);
if(i==){
Thread t1=new Thread(task,"有返回值的线程");
t1.start();
}
}
try {
System.out.println("子线程的返回值:"+task.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}

【运行结果】

【总结】

1.红框内的代码是以Callable对象来启动线程的关键代码。首先使用Lambda表达式创建一个Callable对象,然后将该线程包装成一个FutureTask对象。

2.主线程中,当循环变量i=20时,程序启动以FutureTask对象为target的线程。程序最后调用FutureTask对象的get()方法来返回call()方法的返回值---该方法将导致主线程被阻塞,直到call()方法结束并返回为止。

【采用实现Runnable、Callable接口方式创建多线程】

【优点】
1.线程只是实现了Runable接口或者Callable接口,还可以继承其它类。

2.在这种方式下,多个线程可以共享同一个target对象,比较适合多个相同线程来处理同一份资源的情况。

【缺点】

编程略复杂,如果需要访问当前线程,则必须使用Thread currentThread()方法。

【采用继承Thread类来创建多线程】

【优点】

编写简单,如果需要访问当前线程,只需使用this即可获得当前线程。

【缺点】

因为继承了Thread类,所以不能再继承其他父类。

【分析】

一般推荐采用实现Runnable、Callable接口的方式来创建多线程。

04_线程的创建和启动_使用Callable和Future的方式的更多相关文章

  1. 03_线程的创建和启动_实现Runnable接口方式

    [线程的创建和启动的步骤(实现Runnable接口方式)] 1.定义Runnable接口的实现类,并重写其中的run方法.run()方法的方法体是线程执行体. class SonThread  imp ...

  2. 02_线程的创建和启动_继承Thread方式

    [简述] java使用Thread类代表线程,所有的线程都必须是Thread或者其子类的实例. 每个线程的任务就是完成一定的任务,实际上就是执行一段程序流. [创建并启动多线程的步骤(集成Thread ...

  3. Java线程:创建与启动

    Java线程:创建与启动 一.定义线程   1.扩展java.lang.Thread类.   此类中有个run()方法,应该注意其用法: public void run() 如果该线程是使用独立的 R ...

  4. Netty 学习(七):NioEventLoop 对应线程的创建和启动源码说明

    Netty 学习(七):NioEventLoop 对应线程的创建和启动源码说明 作者: Grey 原文地址: 博客园:Netty 学习(七):NioEventLoop 对应线程的创建和启动源码说明 C ...

  5. Java 线程的创建和启动

    Java 使用 Thread 类代表线程,所有的线程对象都必须是 Thread 类或其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流(一段顺序执行的代码). Java 使用线程执 ...

  6. JAVA学习笔记16——线程的创建和启动

    Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流(一段顺序执行的代码).Java使用线程执行体来代表这段 ...

  7. JavaSE---多线程---线程的创建、启动

    1.概述 1.1 Java中使用Thread类表示线程:   所有的线程对象必须是Thread类 或 其子类的实例:   每条线程的作用:完成一定的任务:   Java中使用run方法来封装线程执行体 ...

  8. Java基础-多线程-①线程的创建和启动

    简单阐释进程和线程 对于进程最直观的感受应该就是“windows任务管理器”中的进程管理: (计算机原理课上的记忆已经快要模糊了,简单理解一下):一个进程就是一个“执行中的程序”,是程序在计算机上的一 ...

  9. Java线程的创建及启动

    1.继承Thread类,重写该类的run()方法. package samTest; import java.util.Scanner; /** * Created by Sam on 2018-01 ...

随机推荐

  1. 【不积跬步,无以致千里】五个常用的Linux监控脚本代码

    为大家提供五个常用Linux监控脚本(查看主机网卡流量.系统状况监控.监控主机的磁盘空间,当使用空间超过90%就通过发mail来发警告.监控CPU和内存的使用情况.全方位监控主机),有需要的朋友不妨看 ...

  2. node.js在windows下的学习笔记(9)---文件I/O模块

    开发中我们经常会有文件I/O的需求,node.js中提供一个名为fs的模块来支持I/O操作,fs模块的文件I/O是对标准POSIX函数的简单封装. 1.将"hello world" ...

  3. Spring技术内幕:Spring AOP的实现原理(二)

    **二.AOP的设计与实现 1.JVM的动态代理特性** 在Spring AOP实现中, 使用的核心技术时动态代理.而这样的动态代理实际上是JDK的一个特性.通过JDK的动态代理特性,能够为随意Jav ...

  4. 插头dp的几个模板

    /* ural1519 求经过全部可行点的哈密顿回路的个数 括号匹配法,转移有点复杂,可是时间空间比較小 */ #include<cstdio> #include<cstring&g ...

  5. [RxJS] ReplaySubject

    A ReplaySubject caches its values and re-emits them to any Observer that subscrubes late to it. Unli ...

  6. android116 轮播 viewPager实现

    布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:to ...

  7. 《Maven_孔浩》Maven介绍及安装

    maven是apache基金会下的一个项目管理工具. 安装步骤 1.下载并解压 2.配置环境变量M2_HOME(解压后的目录):将M2_HOME\bin加入到PATH环境变量中 3.测试:在命令行输入 ...

  8. DOS 命令 attrib:修改文件属性

    有时候系统中病毒之后会把自己的所有文件的属性改为隐藏只读格式,如果手动修改的话太麻烦并且浪费时间,不如用 Attrib 命令试试. 步骤: 1:开始->运行,在里面输入 cmd,打开命令行界面: ...

  9. Linux服务器的常用备份方法

    系统备份是系统管理工作中十分重要的一个环切,本文详细介绍了各种Linux系统的备份方法,相信对大家的日常管理工作有所帮助. 备份是一项重要的工作,但是很多人没有去做.一旦由于使用不当造成数据丢失,备份 ...

  10. Jquery的$命名冲突

    在Jquery中,$是JQuery的别名,所有使用$的地方也都可以使用JQuery来替换,如$('#msg')等同于JQuery('#msg')的写法.然而,当我们引入多个js库后,在另外一个js库中 ...