我们已经知道创建线程的方式有1.继承thread类。2.实现Runnable接口

接下来讲创建线程的新方式Callable接口,首先对比一下Runnable接口和Callable接口的区别:

首先创建两个资源类:分别是实现了Runnable接口和实现了Callable接口:

//Runnable接口
class MyThreadRunnable implements Runnable { @Override
public void run() { }
} //Callable
class MyThreadCallable implements Callable<Integer> { @Override
public Integer call() throws Exception {
System.out.println("******come in here");
return 1024;
}
}

我们可以看到Callable存在泛型,以及返回值,这是对原来的老技术的增强,因为存在了返回值,提高了线程的细粒度。

接着我们看看Runnable创建线程的方式:

//Runnable
MyThreadRunnable myThread1=new MyThreadRunnable();
Thread t1=new Thread(myThread1);

但是通过该方式我们利用Callable来创建线程,却报错了,这是为什么 呢?

原因:Thread并不存在Callable的构造器!

如何创建Callable线程

首先查看API,看Runable接口:

过程如下:

我们可以看到的是,这个构造器需要的参数就是Callable接口的实现类。
所以,我们创建线程的方式如下:

public class CallableDemo {
public static void main(String[] args) {
// MyThreadCallable myThread = new MyThreadCallable();
FutureTask futureTask = new FutureTask(new MyThreadCallable());
new Thread(futureTask, "A").start();
System.out.println(futureTask.get());// 1024 通过get方法来获取返回值
}
}

get方法具有阻塞性

public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// MyThreadCallable myThread = new MyThreadCallable();
FutureTask futureTask = new FutureTask(new MyThreadCallable());
new Thread(futureTask, "A").start();
System.out.println(futureTask.get());// 1024 通过get方式来获取返回值 该方法会阻塞!
System.out.println(Thread.currentThread().getName()+"***计算完成");
}
}
//Callable
class MyThreadCallable implements Callable<Integer> { @Override
public Integer call() throws Exception {
System.out.println("******come in here");
Thread.sleep(5000);
return 1024;
}
}

然后调转依一下主线程与futureTask线程执行的顺序:

public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// MyThreadCallable myThread = new MyThreadCallable();
FutureTask futureTask = new FutureTask(new MyThreadCallable());
new Thread(futureTask, "A").start();
System.out.println(Thread.currentThread().getName()+"***计算完成");
System.out.println(futureTask.get());// 1024 通过get方式来获取返回值 该方法会阻塞!
}
}
//Callable
class MyThreadCallable implements Callable<Integer> { @Override
public Integer call() throws Exception {
System.out.println("******come in here");
Thread.sleep(5000);
return 1024;
}
}

往往futureTask里面的get方法会被阻塞, 所以一般情况下我们先让main线程执行完毕防止由于等待futureTask而耗时。

futureTask的单一性

新增一个线程B:

public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// MyThreadCallable myThread = new MyThreadCallable();
FutureTask futureTask = new FutureTask(new MyThreadCallable());
new Thread(futureTask, "A").start();
new Thread(futureTask, "B").start();
System.out.println(Thread.currentThread().getName() + "***计算完成");
System.out.println(futureTask.get());// 1024 通过get方式来获取返回值 该方法会阻塞!
}
} //Callable
class MyThreadCallable implements Callable<Integer> { @Override
public Integer call() throws Exception {
System.out.println("******come in here");
Thread.sleep(5000);
return 1024;
}
}

只执行了一次,因为一个futureTask,不管几个线程调用,调用的都是同一个futureTask对象!而且Runnable接口就不一样了:

public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThreadRunnable t = new MyThreadRunnable();
Thread thread = new Thread(t);
new Thread(thread).run();
new Thread(thread).run();
}
} //Runnable接口
class MyThreadRunnable implements Runnable { @Override
public void run() {
System.out.println("******come in here");
}
}

以上..

Java高并发,创建线程的新方式Callable接口的更多相关文章

  1. 创建线程之三:实现Callable接口

    通过Callable和Future创建线程 i. 创建Callable接口的实现类,并实现call方法,该call方法将作为线程执行体,并且有返回值,可以抛出异常. ii. 创建Callable实现类 ...

  2. Java高并发与多线程(二)-----线程的实现方式

    今天,我们开始Java高并发与多线程的第二篇,线程的实现方式. 通常来讲,线程有三种基础实现方式,一种是继承Thread类,一种是实现Runnable接口,还有一种是实现Callable接口,当然,如 ...

  3. java高并发系列 - 第11天:线程中断的几种方式

    java高并发系列第11篇文章. 本文主要探讨一下中断线程的几种方式. 通过一个变量控制线程中断 代码: package com.itsoku.chat05; import java.util.con ...

  4. Java多线程并发01——线程的创建与终止,你会几种方式

    本文开始将开始介绍 Java 多线程与并发相关的知识,多谢各位一直以来的关注与支持.关注我的公众号「Java面典」了解更多 Java 相关知识点. 线程的创建方式 在 Java 中,用户常用的主动创建 ...

  5. java高并发系列 - 第6天:线程的基本操作

    新建线程 新建线程很简单.只需要使用new关键字创建一个线程对象,然后调用它的start()启动线程即可. Thread thread1 = new Thread1(); t1.start(); 那么 ...

  6. 跟着阿里p7一起学java高并发 - 第18天:玩转java线程池,这一篇就够了

    java中的线程池,这一篇就够了 java高并发系列第18篇文章. 本文主要内容 什么是线程池 线程池实现原理 线程池中常见的各种队列 自定义线程创建的工厂 常见的饱和策略 自定义饱和策略 线程池中两 ...

  7. java高并发系列 - 第10天:线程安全和synchronized关键字

    这是并发系列第10篇文章. 什么是线程安全? 当多个线程去访问同一个类(对象或方法)的时候,该类都能表现出正常的行为(与自己预想的结果一致),那我们就可以所这个类是线程安全的. 看一段代码: pack ...

  8. Java高并发 -- 线程池

    Java高并发 -- 线程池 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 在使用线程池后,创建线程变成了从线程池里获得空闲线程,关闭线程变成了将线程归坏给线程池. ...

  9. Java高并发--线程安全策略

    Java高并发--线程安全策略 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 不可变对象 发布不可变对象可保证线程安全. 实现不可变对象有哪些要注意的地方?比如JDK ...

  10. 转载:Java高并发,如何解决,什么方式解决

    原文:https://www.cnblogs.com/lr393993507/p/5909804.html 对于我们开发的网站,如果网站的访问量非常大的话,那么我们就需要考虑相关的并发访问问题了.而并 ...

随机推荐

  1. c#12 实验特性Interceptor如何使用的一个简单但完整的示例

    一直有很多转载dotnet对Interceptor说明文档的,但鲜有说明Interceptor如何使用的,这里写一篇简单示例来展示一下 c# 12 实验特性Interceptor 是什么? 官方解释如 ...

  2. Apache DolphinScheduler 1.3.4升级至3.1.2版本过程中的踩坑记录

    因为在工作中需要推动Apache DolphinScheduler的升级,经过预研,从1.3.4到3.1.2有的体验了很大的提升,在性能和功能性有了很多的改善,推荐升级. 查看官方的升级文档,可知有提 ...

  3. devtools工具遇到的坑

    下载devtools一定要下载5.1.1版本,其他版本要么就是下载依赖不行,要么就是打包不行,不清楚的同学会下载最新版,最新版的不能用,切记 地址放这里了: https://github.com/vu ...

  4. win指令学习收集

    要执行多句,需要用到逻辑判断 1 & 2 1成不成功都会执行2 1 && 2 1成功才会执行2 1 || 2 1不成功才会执行2

  5. 查看 Homebrew 管理的服务的日志

    TL;DR 首先找到 log 文件的位置: 对于 macOS (arm64),log 文件在 /opt/homebrew/var/log 目录下 对于 macOS (x86_64),log 文件在 / ...

  6. 用描述程序的方式emo,扎心了...

    用描述程序的方式emo,扎心了... 众所周知写程序是个枯燥无聊的过程,再加上生活的不顺与坎坷,当程序语言与emo结合起来,看谁还说程序员不懂感情! 首当其冲的就是循环语句了 世界上最寂寞的感觉,是我 ...

  7. python将资源打包进exe

    前言 之前py打包的exe一直是不涉及图片等资源的,直到我引入图片后打包,再双击exe发现直接提示未找到资源. 分析 我py代码中的图片引入使用的是项目相对路径,打包时pyinstaller只会引入p ...

  8. Coursera self-driving2, State Estimation and Localization Week2, kalman filter 卡尔曼滤波

    KF - Kalman Filter: EKF - Extended Kalman Filter: ES-EKF - Error State Extended Kalman Filter 和EKF一样 ...

  9. Linux 终端运行命令时出现多行带有加号的信息(详见文章内容)

    ++_vte_ prompt_ command +++ HISTTIMEFORMAT= +++ history 1 +++ sed 's/^ *[0-9] \+ *//' ++ local ' com ...

  10. wxpython开发gui界面基础

    wxpython 开发gui 基础知识 一 .前言 记录使用wxpython开发gui工具吧.gui界面主要就是先布局,每个模块都是一个对象. 二.基础知识 import wx class MyFra ...