目录

  • 线程的创建方式
    • 继承 `Thread` 类
    • 实现 `Runnable` 接口
    • 实现 `Callable` 接口
      • `Futrue、Callable、Runnable、FutureTask` 的继承关系
        • `Callable` 接口
        • `Future` 接口
        • `RunnableFuture` 接口
        • `FutureTask` 类
      • 实现 `Callable` 接口创建线程
    • 线程池创建线程
      • 线程池创建线程之 `Runnable`
      • 线程池创建线程之 `Callable`
  • `Runnable` 与 `Callable` 的区别
    • `Runnable` 与 `Callable` 的源码
  • 文章延伸
    • 线程池的 `execute()` 和 `submit()` 区别

线程的创建方式

线程的创建方式

  • 继承 Thread
  • 实现 Runnable 接口
  • 实现 Callable 接口
  • 线程池创建线程

继承 Thread

public class ThreadTest extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + ":" + i);}}public static void main(String[] args) {new ThreadTest().start();new ThreadTest().start();}
}结果:可能每次结果不相同
Thread-0:0
Thread-1:0
Thread-0:1
Thread-1:1
................省略
Thread-1:8
Thread-0:8
Thread-1:9
Thread-0:9

实现 Runnable 接口

public class ThreadTest implements Runnable {@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println(Thread.currentThread().getName() + ":" + i);}}public static void main(String[] args) {Thread thread1 = new Thread(new ThreadTest());thread1.start();Thread thread2 = new Thread(new ThreadTest());thread2.start();}
}结果:可能每次结果不相同
Thread-0:0
Thread-1:0
Thread-0:1
Thread-1:1
................省略
Thread-0:8
Thread-1:8
Thread-0:9
Thread-1:9

实现 Callable 接口

Futrue、Callable、Runnable、FutureTask 的继承关系

public class FutureTask<V> implements RunnableFuture<V> {}public interface RunnableFuture<V> extends Runnable, Future<V> {void run();
}@FunctionalInterface
public interface Runnable {public abstract void run();
}public interface Future<V> {}

Callable 接口

是一个函数式接口,类泛型参数类型与返回值类型一致,call 方法相当于 Runnablerun() 方法,用来写线程的执行任务

@FunctionalInterface
public interface Callable<V> {V call() throws Exception;
}

Future 接口

Callable 接口只是单纯地去获得返回值,但是什么时候获取,或者查看线程的运行状态,就需要借助 FutureFuture 提供了取消任务、获取任务执行的状态与获取结果的能力

public interface Future<V> {// 取消任务的执行,任务已经完成或者已经被取消时,调用此方法,会返回falseboolean cancel(boolean mayInterruptIfRunning);// 判断任务是否被取消boolean isCancelled();// 判断任务是否完成(正常完成、异常以及被取消,都将返回true)boolean isDone();// 阻塞地获取任务执行的结果V get() throws InterruptedException, ExecutionException;// 在一定时间内,阻塞地获取任务执行的结果V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;}

RunnableFuture 接口

从名字上能看出来,RunnableFuture 继承了 RunnableFuture 接口,run 方法来自 Runnable 接口

public interface RunnableFuture<V> extends Runnable, Future<V> {void run();
}

以上说的,Runnable、Callable、Future 以及 RunnableFuture 都是接口,真正干活还得靠 FutureTask

FutureTask

FutureTask 实现了 RunnableFuture 接口,RunnableFuture 继承了 RunnableFuture 接口,因此 FutureTask 既可以作为一个 RunnableThread 执行,也可以获取到 Future 异步计算的结果

下面看看 FutureTask 类重写 Runnable 接口的 run() 方法

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}public FutureTask(Runnable runnable, V result) {this.callable = Executors.callable(runnable, result);this.state = NEW;       // ensure visibility of callable}public void run() {if (state != NEW ||!UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread()))return;try {Callable<V> c = callable;if (c != null && state == NEW) {V result;boolean ran;try {// 调用了传入的Callable的Call()方法result = c.call();ran = true;} catch (Throwable ex) {result = null;ran = false;setException(ex);}if (ran)set(result);}} finally {// runner must be non-null until state is settled to// prevent concurrent calls to run()runner = null;// state must be re-read after nulling runner to prevent// leaked interruptsint s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}}
}

可看出,run() 方法调用了传入的 Callablecall() 方法

实现 Callable 接口创建线程

public class CallableFutureTest {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask futureTask = new FutureTask(new Callable() {@Overridepublic Object call() throws Exception {System.out.println(Thread.currentThread().getName());return 200;}});// FutureTask实现了Runnable接口,用Runnable创建一个线程// 注意这里,这里传入futureTask参数,构造了一个Threadnew Thread(futureTask).start();int result = (int) futureTask.get(); // 获取线程的最终结果System.out.println("result的结果:" + result);System.out.println("main come over");}
}结果:
Thread-0
result的结果:200
main come over

线程池创建线程

使用 ThreadPoolExecutor 类中的 execute() 方法来创建线程

关于线程池 ThreadPoolExecutor 类的详情:https://blog.csdn.net/weixin_38192427/article/details/117394526

线程池创建线程之 Runnable

public class ThreadPoolTest {public static void main(String[] args) {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 100, TimeUnit.SECONDS,new ArrayBlockingQueue<>(100), new ThreadPoolExecutor.AbortPolicy());for (int i = 0; i < 10; i++) {threadPoolExecutor.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}});}/*关闭线程池*/threadPoolExecutor.shutdown();while (!threadPoolExecutor.isTerminated()) {}System.out.println("main come over");}
}结果:
pool-1-thread-1
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-1
pool-1-thread-3
pool-1-thread-2
pool-1-thread-1
pool-1-thread-4
pool-1-thread-5
main come over

线程池创建线程之 Callable

public class ThreadPoolTest2 {public static void main(String[] args) {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 100, TimeUnit.SECONDS,new ArrayBlockingQueue<>(100), new ThreadPoolExecutor.AbortPolicy());for (int i = 0; i < 10; i++) {/*使用FutureTask的构造函数实例化*/FutureTask futureTask = new FutureTask(new Callable() {@Overridepublic Object call() throws Exception {System.out.println(Thread.currentThread().getName());return 200;}});/*由于FutureTask间接的实现了接口Runnable,所以此处可以传递参数futureTask*/threadPoolExecutor.execute(futureTask);}/*关闭线程池*/threadPoolExecutor.shutdown();while (!threadPoolExecutor.isTerminated()) {}System.out.println("main come over");}
}结果:
pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-4
pool-1-thread-5
main come over

RunnableCallable 的区别

RunnableCallable 的源码

@FunctionalInterface
public interface Runnable {public abstract void run();
}@FunctionalInterface
public interface Callable<V> {V call() throws Exception;
}
  • Callcble 是有返回值的,返回值是通过实现 Future 接口的对象的 get 方法获取的,这个方法是会造成线程阻塞的;而 Runnable 是没有返回值的,因为 Runnable 接口中的 run() 方法是没有返回值的
  • Callable 里面的 call() 方法是可以抛出异常的,我们可以捕获异常进行处理;但是 Runnable 里面的 run() 方法是不可以抛出异常的,异常要在 run() 方法内部必须得到处理,不能向外界抛出

文章延伸

线程池的 execute()submit() 区别

  • execute() 方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;execute() 方法的实现是 ThreadPoolExecutor 类中
public interface Executor {void execute(Runnable command);
}
  • submit() 方法用于提交需要返回值的任务。线程池会返回一个 Future 类型的对象,通过这个 Future 对象可以判断任务是否执行成功,并且可以通过 Futureget() 方法来获取返回值,get() 方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit) 方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完
public interface ExecutorService extends Executor {// ...........................省略<T> Future<T> submit(Runnable task, T result);// ...........................省略
}
public abstract class AbstractExecutorService implements ExecutorService {public Future<?> submit(Runnable task) {if (task == null) throw new NullPointerException();RunnableFuture<Void> ftask = newTaskFor(task, null);execute(ftask);return ftask;}public <T> Future<T> submit(Runnable task, T result) {if (task == null) throw new NullPointerException();RunnableFuture<T> ftask = newTaskFor(task, result);execute(ftask);return ftask;}// ......
}

线程的创建方式及Runnable与Callable的区别相关推荐

  1. JAVA 三种线程实现创建方式

    JAVA 三种线程实现/创建方式 方式一:继承Thread类 通过继承Thread类来创建一个自定义线程类.Thread类本质上就继承了Runable接口,代表一个线程类.启动线程的唯一办法就是通过T ...

  2. Runnable和Callable的区别:

    Runnable和Callable的区别: (1)Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的(2)Callable规定的方法是call(),Runnable规 ...

  3. java中Runnable和Callable的区别

    文章目录 运行机制 返回值的不同 Exception处理 java中Runnable和Callable的区别 在java的多线程开发中Runnable一直以来都是多线程的核心,而Callable是ja ...

  4. java启动100线程_Java启动新线程的几种方式(Runnable、Callable、CompletableFuture)

    一.实现Runnable接口 public classRunnableDemo implements Runnable {public voidrun() {try{ Thread.sleep(100 ...

  5. Java并发编程(01):线程的创建方式,状态周期管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.并发编程简介 1.基础概念 程序 与计算机系统操作有关的计算机程序.规程.规则,以及可能有的文件.文档及数据. 进程 进程是计算机中的程序 ...

  6. Java线程的创建方式

    文章目录 创建线程的几种方法: ①继承Thread类 ②实现Rullable接口 ③实现Callable接口 Callable接口 Future 接口 FutureTask类 ④使用线程池 Runab ...

  7. Java 的Runnable和Callable的区别

    Runnable和Callable的区别是, (1)Callable规定的方法是call(),Runnable规定的方法是run(). (2)Callable的任务执行后可返回值,而Runnable的 ...

  8. java 中线程的创建方式

    如果说在java中创建线程的有几种方式的话,归根结底我认为就两种方式 1.继承Thread类,重写run方法 继承Thread类,如下图重写了run()方法 通过start()方法来启动线程 最后的输 ...

  9. Runnable 和 Callable 的区别

    区别 两个都是接口,但是 Runnable 方法中 run() 没有声明异常且没有返回值,而 Callable 中 call() 声明了异常且有返回值:(意味着使用 Runnable 需要自己处理异常 ...

  10. Runnable 与 Callable 的区别

    1. 类结构 Runnable: @FunctionalInterface public interface Runnable {public abstract void run(); } Calla ...

最新文章

  1. python教学反思_Python第3课if教学反思:准备充分承上启下,优化内容模式初显
  2. day 81 天 ORM 操作复习总结
  3. 纯php socket mysql_PHP 连接 unix_socket MySQL
  4. 案例解析|广东自由流收费稽核方案,AI稽核新模式
  5. IE中如何屏蔽窗口关闭
  6. BZOJ1853: [Scoi2010]幸运数字(容斥原理)
  7. 安装centos7的电脑对比视频播放
  8. Team Foundation Server XXX 不存在,或者此时不可访问:解决方案
  9. linux上卓懿应用商城王者荣耀键盘映射如何设置?
  10. mysql 数据库快速入门 数据库的发展
  11. App Store审核宝典
  12. 模块化机房建设指导书_模块化机房建设方案
  13. 微信公众号视频下载教程
  14. VLOOKUP多条件匹配
  15. html 隐藏广告代码,js漂浮广告原理 js或者CSS带关闭的漂浮广告代码
  16. 佐治亚理工计算机科学,Gatech的CS「佐治亚理工学院计算机科学系」
  17. python 爬虫学习之 selenium.webdriver学习
  18. 【学习周报9.26 ~ 10.1】Hierarchical Modular Network for Video Captioning(CVPR2022)
  19. NLP经典论文:Sequence to Sequence、Encoder-Decoder 、GRU 笔记
  20. 离散数学中Warshall算法简析

热门文章

  1. 算法: 最大矩形面积85. Maximal Rectangle
  2. hive出现内存溢出_hive问题处理
  3. mysql自动跑sql发邮件_SQL server 表数据改变触发发送邮件的方法
  4. amd玄冰400怎么拆图解_【装机帮扶站】第735期:“无货”当道的京东年底大预售来了(AMD篇)...
  5. 逻辑斯蒂回归模型为什么用sigmoid函数
  6. Linux4755文件权限,如何在Linux中管理文件和文件夹的权限
  7. mysql5.7 字符集编码
  8. SVM入门(五)线性分类器的求解——问题的描述Part2
  9. org.apache.hadoop.hbase.mapreduce.Driver 导入数据到HBASE table
  10. c语言经典面试题 洗牌,网易游戏面试题:如何设计一个公平的洗牌算法