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接口创建线 ...
随机推荐
- Android开发如何定制framework层服务
刚刚跨完年,新年第一篇文章,那么今天将对Android开发framework中间层的服务定制使用作个总结.首先我们先导入Android平台源码framework层的代码到开发工具eclipse中,代码 ...
- VMware下Linux配置局域网和外网访问(CentOS)
要使用Linux系统很重要的一个操作就是使Linux系统能够访问互联网,只有Linux系统能够访问互联网才能够去下载很多自己所需要的资源,如果不能访问互联网那么使用Linux系统往往会卡在这一步,假设 ...
- 【转】c++ http下载文件
#include <afx.h> #include <afxinet.h> #define RECVPACK_SIZE 2048 bool DownloadSaveFiles( ...
- 毕向东_Java基础视频教程第20天_IO流(11~14)
第20天-11-IO流(Properties简述) .properties是一种主要在Java相关技术中用来存储应用程序的可配置参数的文件的文件扩展名.它们也可以存储用于国际化和本地化的字符串,这种文 ...
- js:自动亮起100盏灯
1) 使用js在页面上显示100盏灯,并标记从1到100的编号2) 页面加载后3秒,从编号是1的灯依次自动亮起.3) 每过0.5秒亮下一盏灯(10分)4) 所有灯亮起后,弹出确 ...
- Excel VBA开发
一.Excel添加treeview控件 如果是以VBA中为窗体添加,菜单:工具->附加控件,从中选择“Microsoft TreeView Control”: 在控件工具箱中点击其它控件,从中选 ...
- POP动画[3]
POP动画[3] 这一节主要讲解POP动画的自定义动画属性. POP动画中有一个参数,叫timingFunction,与CoreAnimation中的一个参数CAMediaTimingFunction ...
- linux 无法安装gcc, 可以试试换用 阿里的yum
1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2.下载新的CentOS-Base ...
- Java学习---程序设计_基础题[1]
180813 补全没有的答案! 0. 数组排序大全[冒泡/选择/快速/插入] package com.ftl; import java.io.BufferedReader; import java.i ...
- Linux NFS 详解
目录: 1.了解NFS服务 2.NFS主要文件 3.NFS安装 4.NFS配置 5.NFS客户端配置 6.固定NFS端口 7.Windows挂 ...