Java多线程之线程的启动
Java多线程之线程的启动
一、前言
启动线程的方法有如下两种。
- 利用Thread 类的子类的实例启动线程
- 利用Runnable 接口的实现类的实例启动线程
最后再介绍下java.util.concurrent.ThreadFactory中的线程创建
下面分别做以介绍
二、利用Thread 类的子类启动线程
这里来学习一下利用Thread 类的子类的实例来启动线程的方法,即上一篇博文中使用的方法。我们构造一个PrintThread 类表示输出1000次指定字符串的线程。输出的字符串通过构造函数的参数传入,并赋给message 字段。PrintThread 类被声明为Thread 的子类。
如下表示输出10 000 次指定字符串的线程的类PrintThread(PrintThread.java)
public class PrintThread extends Thread {
private String message;
public PrintThread(String message) {
this.message = message;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(message);
}
}
}
Main 类是用于创建上面声明的PrintThread 类的两个实例并利用它们来启动两个线程的程序。
利用PrintThread 类启动2 个线程(Main.java)
public class Main {
public static void main(String[] args) {
new PrintThread("Good!").start();
new PrintThread("Nice!").start();
}
}
main 方法创建了PrintThread 类的实例,并直接(不赋给某个变量)调用了该实例的start 方法。
start 方法会启动新的线程,然后由启动的新线程调用PrintThread 类的实例的run 方法。
最终结果就是由新启动的线程执行1000次Good! 字符串输出。
为了程序简洁,上面的程序只用一条语句启动了线程。但实际上,“创建PrintThread 的实例”和“启动该实例对应的线程”是两个完全不同的处理。也就是说,即便已经创建了实例,但是如果不调用start 方法,线程也不会被启动。上面这条语句也可以像下面这样写成两句。
另外,这里再提醒大家注意,“PrintThread 的实例”和“线程本身”不是同一个东西。即便创建了PrintThread 的实例,线程也并没有启动,而且就算线程终止了,PrintThread 的实例也不会消失。
主线程在Main 类的main 方法中启动了两个线程。随后main 方法便会终止,主线程也会跟着终止。但整个程序并不会随之终止,因为启动的两个线程在字符串输出之前是不会终止的。直到所有的线程都终止后,程序才会终止。也就是说,当这两个线程都终止后,程序才会终止。
关于程序的终止:
Java 程序的终止是指除守护线程(Daemon Thread)以外的线程全部终止。守护线程是执行后台作业的线程。我们可以通过setDaemon 方法把线程设置为守护线程。
创建Thread 类的子类、创建子类的实例、调用start 方法——这就是利用Thread 类的子类启动线程的方法。
三、利用Runnable 接口启动线程
这里来学习一下利用Runnable 接口的实现类的实例来启动线程的方法。Runnable 接口包含在java.lang 包中,声明如下。
public interface Runnable {
public abstract void run();
}
Runnable 接口的实现类必须要实现run 方法,否则要声明为抽象方法。
现在我们来构造Printer类表示一个输出10 000 次指定字符串的线程。输出的字符串通过构造函数的参数传入,并赋给message 字段。由于Printer 类实现(implements)了Runnable 接口,所以此时也就无需再将Printer 类声明为Thread 类的子类。
输出指定字符串的Printer 类(Printer.java)
public class Printer implements Runnable {
private String message;
public Printer(String message) {
this.message = message;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(message);
}
}
}
Main 类是用于创建两个Printer 类的实例,并利用它们来启动两个线程的程序。
利用Runnable 接口启动两个线程(Main.java)
public class Main {
public static void main(String[] args) {
new Thread(new Printer("Good")).start();
new Thread(new Printer("Nice")).start();
}
}
创建Thread 的实例时,构造函数的参数中会传入Printer 类的实例,然后会调用start 方法,启动线程。
start 方法会启动新的线程,然后由启动的新线程调用Printer 类的实例的run 方法。最终结果就是由新启动的线程执行1000次Good! 字符串输出。上面这条语句也可以像下面这样写成三句。
创建Runnable 接口的实现类,将实现类的实例作为参数传给Thread 的构造函数,调用start 方法——这就是利用Runnable 接口启动线程的方法。
不管是利用Thread 类的子类的方法(1),还是利用Runnable 接口的实现类的方法(2),启动新线程的方法最终都是Thread 类的start 方法。
关于Thread 类和Runnable 方法
Thread 类本身还实现了Runnable 接口,并且持有run 方法,但Thread 类的run 方法主体是空的,不执行任何操作。Thread 类的run 方法通常都由子类的run 方法重写(override)。
四、java.util.concurrent.ThreadFactory 中的线程创建
java.util.concurrent 包中包含一个将线程创建抽象化的ThreadFactory 接口。利用该接口,我们可以将以Runnable 作为传入参数并通过new 创建Thread 实例的处理隐藏在ThreadFactory 内部。典型用法如下所示。默认的ThreadFactory 对象是通过Executors.defaultThreadFactory 方法获取的。
此处运行的Printer类与上面的Printer 类相同
利用ThreadFactory 新启动线程(Main.java)
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
public class Main2 {
public static void main(String[] args) {
ThreadFactory factory = Executors.defaultThreadFactory();
factory.newThread(new Printer("Good!")).start();
for (int i = 0; i < 1000; i++) {
System.out.println("Nice!");
}
}
}
参考:图解Java多线程设计模式
Java多线程之线程的启动的更多相关文章
- Java多线程之线程其他类
Java多线程之线程其他类 实际编码中除了前面讲到的常用的类之外,还有几个其他类也有可能用得到,这里来统一整理一下: 1,Callable接口和Future接口 JDK1.5以后提供了上面这2个接口, ...
- Java多线程之线程的同步
Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...
- Java多线程之线程的控制
Java多线程之线程的控制 线程中的7 种非常重要的状态: 初始New.可运行Runnable.运行Running.阻塞Blocked.锁池lock_pool.等待队列wait_pool.结束Dea ...
- Java多线程02(线程安全、线程同步、等待唤醒机制)
Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...
- java多线程与线程间通信
转自(http://blog.csdn.net/jerrying0203/article/details/45563947) 本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程 ...
- Java多线程之线程的生命周期
Java多线程之线程的生命周期 一.前言 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(R ...
- Java多线程| 01 | 线程概述
Java多线程| 01 | 线程概述 线程相关概念 进程与线程 进程:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是操作系统进行资源分配与调度的基本单位.可以把进程简单的理解 ...
- Java多线程之线程的通信
Java多线程之线程的通信 在总结多线程通信前先介绍一个概念:锁池.线程因为未拿到锁标记而发生的阻塞不同于前面五个基本状态中的阻塞,称为锁池.每个对象都有自己的锁池的空间,用于放置等待运行的线程.这些 ...
- Java多线程父子线程关系 多线程中篇(六)
有的时候对于Java多线程,我们会听到“父线程.子线程”的概念. 严格的说,Java中不存在实质上的父子关系 没有方法可以获取一个线程的父线程,也没有方法可以获取一个线程所有的子线程 子线程的消亡与父 ...
随机推荐
- MyEclipse2014破解版
百度云:链接:http://pan.baidu.com/s/1c3jKMa 密码:yss0 等版本)后,不要打开软件. 二.解压破解文件压缩包,得到一下文件列表: 三.双击run.bat,即可运行cr ...
- (读论文)推荐系统之ctr预估-NFM模型解析
本系列的第六篇,一起读论文~ 本人才疏学浅,不足之处欢迎大家指出和交流. 今天要分享的是另一个Deep模型NFM(串行结构).NFM也是用FM+DNN来对问题建模的,相比于之前提到的Wide& ...
- RobotFramework_4.SeleniumLibrary操作(二)
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- K8S 部署 Web UI
在早期的版本中 Kubernetes可以在 Dashboard 中看到 heapster 提供的一些图表信息, 在后续的版本中会陆续移除掉 heapster,现在更加流行的监控工具是 promethe ...
- spring boot中的声明式事务管理及编程式事务管理
这几天在做一个功能,具体的情况是这样的: 项目中原有的几个功能模块中有数据上报的功能,现在需要在这几个功能模块的上报之后生成一条消息记录,然后入库,在写个接口供前台来拉取消息记录. 看到这个需求,首先 ...
- nginx lua集成kafka
NGINX lua集成kafka 第一步:进入opresty目录 [root@node03 openresty]# cd /export/servers/openresty/ [root@node03 ...
- luogu1220_关路灯 区间dp
传送门 区间dp f[i][j][state] : [i, j]区间 state=0 当前选i state = 1 当前选j 注意枚举的顺序 转移的设计时 在同时刻不在[i,j]区间里的数也要考虑 不 ...
- python异常处理-异常捕获-抛出异常-断言-自定义异常-UDP通信-socketserver模块应用-3
异常捕获 异常:程序在运行过程中出现了不可预知的错误,并且该错误没有对应的处理机制,那么就会以异常的形式表现出来 影响:整个程序无法再正常运行 异常的结构 异常的类型 NameError 异常的信息 ...
- RocketMq中网络通信之服务端
一,Broker服务端入口(NettyServer端) 首先RocketMq网络通信采用的Netty通信.服务端主要集中在Broker中.我们先看一下Broker的启动类BrokerStartup 显 ...
- Linux下SVN库迁移
在日常的工作中,可能因为一些服务器硬件损坏等问题,不得不把SVN服务器上的SVN版本库进行迁移,下面讲解一下SVN库迁移方案(采用dump & load方案),在实际操作的时候也非常的简单,有 ...