Java并发编程(二)创建线程的三种方法
进程与线程
1. 进程
进程和代码之间的关系就像音乐和乐谱之间的关系一样,演奏结束的时候音乐就不存在了但乐谱还在;程序执行结束的时候进程就消失了但代码还在,而计算机就是代码的演奏家。
2. 线程
线程可以比喻成演奏过程中的某一种乐器的声音,乐器声音的种类可以很少,但是不能一个都没有——一个进程至少包含一个线程。线程是程序执行的核心,就像没有了具体乐器的声音就没有了音乐一样。
创建线程的三种方式
1. 继承Thread方法
1). 定义线程类
继承Thread方法时,需要重写Thread的run()方法。run()方法中的代码就是你要并发执行的代码。
class ExampleThread extends Thread {
@Override
public void run() {
doSomething();
}
}
2). 执行线程类的代码
在main()方法里创建一个ExampleThread对象,调用该对象的start()方法,start()方法会通过对系统底层的一系列操作,创建出一个相应的线程,与当前线程并发执行。如果直接调用run()方法,程序将执行完run()方法后才会执行main()方法中后面的代码,这样就是单线程执行而不是多线程并发执行了。
public class CreateThread {
public static void main(String[] args) {
ExampleThread thread = new ExampleThread();
thread.start();//注意是start(),不是run()
//下面的代码可以和run()方法里的代码并发执行
doSomethingElse();
}
}
2. 实现Runnable接口
1). 定义线程类
使用Runnable接口与继承Thread类的用法类似,也是在新的类中编写run()方法,方法中的内容就是新建线程要执行的代码。
class ExampleThread implements Runnable {
@Override
public void run() {
doSomething();
}
}
2). 执行线程类的代码
实现Runnable接口的类中没有start()方法,因此我们应该为这个线程“找一个”start()方法。Thread类有一个带Runnable参数的构造方法,我们将ExampleThread的对象作为参数传到Thread的构造方法中,这时候再调用Thread对象的start()方法就可以生成一个线程了,是不是有种“借鸡生蛋”的感觉。
public class CreateThread {
public static void main(String[] args) {
Runnable runnable = new ExampleThread()
Thread thread = new Thread(runnable);
thread.start();//注意是start(),不是run()
//下面的代码可以和run()方法里的代码并发执行
doSomethingElse();
}
}
3. 实现Callable接口
1). 定义线程类
前面说的使用Thread和Runnable实现多线程的方法都不能从上一个线程中得到返回值,可是有些时候当一个线程运行结束的时候你想让它返回一些有价值的信息,比如某些操作是否执行成功了。Callable接口就是用于解决这类问题的,Callable接口是一个带泛型的接口,泛型的类型就是线程返回值的类型。实现Callable接口中的call()方法,方法的返回类型与泛型的类型相同。
class ExampleThread implements Callable<String> {
@Override
public String call() {
doSomething();
return "Some Value";
}
}
2). 执行线程类的代码
执行这个线程类的方法与Runnable类似,但是Callable在调用start()方法之前需要先包一层FutureTask,FutureTask用于获得线程返回的数值,具体代码如下:
public class CreateThread {
public static void main(String[] args) {
Callable<String> callable = new ExampleThread();
FutureTask<String> task = new FutureTask<String>(callable);
Thread thread = new Thread(task);
thread.start();//注意是start(),不是call()
doSomethingElse();
try {
String returnVal = task.get();//这里就得到了线程的返回值
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
这里有一个需要注意的地方,当调用task.get()的时候,新创建的线程可能还没有执行完,这时调用get()方法当前线程就会被阻塞,直到新创建的线程执行结束。因此,task.get()代码最好是在当前线程不得不用这个返回值时再调用,这样当前线程可以继续执行与返回值无关的代码。
总结
通过继承Thread类和实现Runnable接口生成的线程都是没有返回值的,实现Callable接口的线程可以有返回值,但是要注意不要过早的阻塞当前线程。
继承Thread类和实现Runnable接口二者之间各有好处,继承Thread类可以方便的使用到start()方法启动线程,但同时也带来一个弊端:继承使新类和Thread类产生强耦合,此外,由于Java不支持多继承,新的类也不能再继承其他的类。实现Runnable接口与之相反。
那么问题来了,Thread和Runnable该如何选择呢?我的建议是尽量使用Runnable,有的人可能会说:用Runnable还是要调用Thread的start()方法,还不如直接用Thread呢。嘿嘿,其实线程池可以代替Thread的start(),预知详情,且看下文分解。公众号:今日说码。关注我的公众号,可查看连载文章。遇到不理解的问题,直接在公众号留言即可。
Java并发编程(二)创建线程的三种方法的更多相关文章
- JAVA并发编程学习笔记------线程的三种创建方式
创建线程一般有如下几个方式: 1. 通过继承Thread类来创建一个线程: /** * 步骤1:定义一个继承Thread类的子类 * 步骤2:构造子类的一个对象 * 步骤3:启动线程: * */ pu ...
- 《Java多线程面试题》系列-创建线程的三种方法及其区别
1. 创建线程的三种方法及其区别 1.1 继承Thread类 首先,定义Thread类的子类并重写run()方法: package com.zwwhnly.springbootaction.javab ...
- java创建线程的三种方法
这里不会贴代码,只是将创建线程的三种方法做个笼统的介绍,再根据源码添加上自己的分析. 通过三种方法可以创建java线程: 1.继承Thread类. 2.实现Runnable接口. 3.实现Callab ...
- java多线程编程(二创建线程)
1.概念 因为java是完全面向对象的,所以在java中,我们说的线程,就是Thread类的一个实例对象.所以,一个线程就是一个对象,它有自己字段和方法. 2.创建线程 创建线程有 ...
- 0036 Java学习笔记-多线程-创建线程的三种方式
创建线程 创建线程的三种方式: 继承java.lang.Thread 实现java.lang.Runnable接口 实现java.util.concurrent.Callable接口 所有的线程对象都 ...
- python 多线程编程之threading模块(Thread类)创建线程的三种方法
摘录 python核心编程 上节介绍的thread模块,是不支持守护线程的.当主线程退出的时候,所有的子线程都将终止,不管他们是否仍在工作. 本节开始,我们开始介绍python的另外多线程模块thre ...
- JAVA中创建线程的三种方法及比较
JAVA中创建线程的方式有三种,各有优缺点,具体如下: 一.继承Thread类来创建线程 1.创建一个任务类,继承Thread线程类,因为Thread类已经实现了Runnable接口,然后重写run( ...
- Java基础_线程的使用及创建线程的三种方法
线程:线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 进程:进 ...
- Java中创建线程的三种方法以及区别
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例.Java可以用三种方式来创建线程,如下所示: 1)继承Thread类创建线程 2)实现Runnable接口创建线 ...
随机推荐
- C语言——无向带权图邻接矩阵的建立
#include <stdio.h> #include "Graph.h" #define MAX_INT 32767 /* #define vnum 20 #defi ...
- Java 中你必须了解的常用类(8)
Java 中的包装类 相信各位小伙伴们对基本数据类型都非常熟悉,例如 int.float.double.boolean.char 等.基本数据类型是不具备对象的特性的, 比如基本类型不能调用方法.功能 ...
- Android链接蓝牙电子称
蓝牙一直是我内心屏蔽的一个模块哈哈哈哈!然而今天我不得不正视它了,我百度了看了好多因为需要设备匹配所以设备不在没办法测试,几天之后设备到了.因为没有接触过,看到返回的打印出来的菱形方块就以为是错了.于 ...
- 有关平台支持的从经典部署模型到 Azure Resource Manager 的迁移的技术深入探讨
本文将深入探讨如何从 Azure 经典部署模型迁移到 Azure Resource Manager 部署模型. 本文将介绍资源和功能级别的资源,让用户了解 Azure 平台如何在两种部署模型之间迁移资 ...
- jquery遍历之children()与find()的区别
hildren(selector) 方法是返回匹配元素集合中每个元素的所有子元素(仅儿子辈).参数可选,添加参数表示通过选择器进行过滤,对元素进行筛选. .find(selector)方法是返回匹配元 ...
- iOS设计模式 - 适配器
iOS设计模式 - 适配器 效果 说明 1. 为了让客户端尽可能的通用,我们使用适配器模式来隔离客户端与外部参数的联系,只让客户端与适配器通信. 2. 本教程实现了适配器模式的类适配器与对象适配器两种 ...
- awk 截取某段时间的日志
好久没有截取nginx/haproxy 中 的日志了,竟有点不熟悉了. 记录一下,以免以后忘记. NGINX 日志格式: 192.168.1.26 - - [14/Sep/2017:16:48:42 ...
- 导出当前域内所有用户hash的技术整理
0x00目标: 导出当前域内所有用户的hash 0x01测试环境: 域控:server2008 r2 杀毒软件:已安装* 域控权限:可使用net use远程登陆,不使用3389 0x02测试方法: ( ...
- 1、关于python第三方工具操作xls和xlsx格式的excel文档选型的吐血经历
首先,最近看了python的一本书,其中第7章是关于文章操作的,就计划把python操作excel,word,txt,xml,html,json等格式的文档做个总结,并实现一些功能,但是,第一步就要把 ...
- 洛谷 P4841 城市规划
构造简单无向图的EGF: \[ G(x)=\sum_{i}^{\infty}2^{\binom{i}{2}}\cdot\frac{x^i}{i!} \] 构造简单无向连通图的EGF: \[ F(x)= ...