Java并发编程之线程创建和启动(Thread、Runnable、Callable和Future)
这一系列的文章暂不涉及Java多线程开发中的底层原理以及JMM、JVM部分的解析(将另文总结),主要关注实际编码中Java并发编程的核心知识点和应知应会部分。
说在前面,Java并发编程的实质,是线程对象调用start方法启动多线程,而线程对象则必须是Thread类或其子类实现。Runnable和Callable的作用类似于Comparable、Serializable,是用于被并发的类实现的接口,从而使得Thread类可以在初始化时传入这个被并发的类。此是大前提。本文从多线程实现和启动出发,对这些类或接口予以说明。
Thread
通过Thread的子类创建多线程的步骤如下:
1. 创建Thread的子类,并重写run()方法,该方法即为线程执行体。
2. 创建Thread子类的对象,即为线程对象。
3. 调用线程对象的start()方法启动线程。
1 public class TestThread extends Thread{ 2 3 public TestThread(String name) { 4 setName(name); 5 } 6 @Override 7 public void run() { 8 while(!interrupted()) 9 System.out.println(getName() + "线程执行了"); 10 } 11 public static void main(String[] args) { 12 13 TestThread t1 = new TestThread("first"); 14 TestThread t2 = new TestThread("second"); 15 //setDaemon()设置线程为守护线程 16 // t1.setDaemon(true); 17 // t2.setDaemon(true); 18 t1.start(); 19 t2.start(); 20 t1.interrupt(); 21 } 22 }
Runnable
需要并发执行的类,可以通过实现Runnable接口,作为Thread的Target来创建线程对象。
1 public class TestRunnable implements Runnable{ 2 3 @Override 4 public void run() { 5 while(true) { 6 System.out.println("thread running..."); 7 try { 8 Thread.sleep(1000); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } 12 } 13 } 14 15 public static void main(String[] args) { 16 //传入TestRunnable对象作为Target, 开启线程 17 Thread t = new Thread(new TestRunnable()); 18 t.start(); 19 //采用匿名内部类的方式创建和启动线程 20 new Thread() { 21 @Override 22 public void run() { 23 System.out.println("Thread的匿名内部类"); 24 } 25 }.start(); 26 //父类采用匿名实现Runnable接口, 并由子类继承 27 new Thread(new Runnable() { 28 29 @Override 30 public void run() { 31 System.out.println("父类的线程"); 32 } 33 }) { 34 @Override 35 public void run() { 36 System.out.println("子类的线程"); 37 } 38 }.start(); 39 } 40 }
Callable和Future
Java5开始提供了Callable接口,用于现有多线程开发的强力补充。Callable接口提供一个call()方法来构造线程执行体。
1. call()方法可以有返回值
2. call()方法可以声明抛出异常
因此Callable接口没有继承Runnable接口,不能直接作为Thread类的Target来构造线程对象,所以Java5提供了Future接口来代表call方法的返回值。
Future提供了FutureTask实现类,该实现类实现了Future接口和Runnable接口,像桥梁一样把线程执行体和线程对象连接了起来。
Future接口提供了若干公共方法来操作Callable任务:
- boolean cancel(boolean mayInterruptIfRunning): 试图取消Future里关联的Callable任务
- V get():返回Callable任务里call方法的返回值。调用该方法会导致阻塞,必须等子线程完成后才得到返回值
- V get(long timeout, TimeUnit unit):最多阻塞timeout和unit指定的时间,超时将抛出TimeoutException异常
- boolean isCancelled():Callable任务正常完成前被取消,则返回true
- boolean isDone():Callable任务已完成,则返回true
创建并启动有返回值的线程步骤如下:
1. 创建Callable接口的实现类,并实现call方法作为线程执行体,再创建类的实例。Java8中可通过Lambda表达式进行。
2. 使用FutureTask类来包装Callable实现类的对象
3. 使用FutureTask作为Thread对象的target
4. 使用FutureTask对象的get方法获取子线程执行后的返回值
Callable接口和FutureTask实现类的底层是基于接口回调技术实现,具体可参考:基于接口回调详解JUC中Callable和FutureTask实现原理
1 public class TestCallable implements Callable<Integer>{ 2 //实现Callable并重写call方法作为线程执行体, 并设置返回值1 3 @Override 4 public Integer call() throws Exception { 5 System.out.println("Thread is running..."); 6 Thread.sleep(3000); 7 return 1; 8 } 9 10 public static void main(String[] args) throws InterruptedException, ExecutionException { 11 //创建Callable实现类的对象 12 TestCallable tc = new TestCallable(); 13 //创建FutureTask类的对象 14 FutureTask<Integer> task = new FutureTask<>(tc); 15 //把FutureTask实现类对象作为target,通过Thread类对象启动线程 16 new Thread(task).start(); 17 System.out.println("do something else..."); 18 //通过get方法获取返回值 19 Integer integer = task.get(); 20 System.out.println("The thread running result is :" + integer); 21 } 22 }
总结一下,虽然继承Thread类的开发方式相对简单,但因为Java单继承的限制,一般建议通过实现Runnable或Callable接口来创建并启动多线程。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
零基础学python,看完这篇文章,你的python基础就差不多了!干货
Python基础语法和面向对象(下一篇分享面向对象) Python基础语法 1. 认识Python 1.1 Python 简介 Python 的创始人为吉多·范罗苏姆(Guido van Rossum)。 Python 的设计目标: 一门简单直观的语言并与主要竞争者一样强大 开源,以便任何人都可以为它做贡献 代码像纯英语那样容易理解 适用于短期开发的日常任务 Python 的设计哲学: 优雅、明确、简单 Python 开发者的哲学是:用一种方法,最好是只有一种方法来做一件事 Python 是完全面向对象的语言,在 Python 中一切皆对象。 可扩展性:如果需要一段关键代码运行得更快或者希望某些算法不公开,可以把这部分程序用 C 或 C++ 编写,然后在 Python 程序中使用它们。 1.2. 第一个Python程序 执行 Python 程序的三种方式: 解释器、交互式运行、IDE运行 Python 是一个格式非常严格的程序设计语言。 python 2.x 默认不支持中文。 ASCII 字符只包含 256 个字符,不支持中文 Python 2.x 的解释器名称是python Py...
-
下一篇
Rxjava深入理解之自己动手编写Rxjava
Demo的源码地址在 mini-rxjava, 有兴趣的可以下载源码来看. 从观察者模式说起 观察者模式,是我们在平时使用的比较多的一种设计模式.观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 它的特点是 一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。 本文的重点不是在介绍 观察者模式,因此这个话题就不展开讨论. Rxjava 是一种 函数式编程,或者称为链式调用模型,也是使用观察者模式来实现事件的传递与监听. 下面我们来看,Rxjava 和 普通观察者的点区别. 普通的观察者模式通常是 一个主题,多个观察者配合,基本上是属于 一对多的情况. Rxjava的观察者模式通常是 一对一的关系. 普通的观察者模式是 主题数据改变时,通知观察者数据的变动 Rxjava的观察者模式是 在被观察者(主题)调用subscribe方法后,触发数据流动和观察者接收事件. 基础知识介绍到这里,接下来我们来自己动手编写Rxjava 编写Rxjava 看一个常见的rx...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2全家桶,快速入门学习开发网站教程
- Dcoker安装(在线仓库),最新的服务器搭配容器使用
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- MySQL8.0.19开启GTID主从同步CentOS8
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- MySQL数据库在高并发下的优化方案
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果