Java多线程系列 基础篇02 线程的创建和运行
1.线程创建的方式常用有两种
1. 继承 Thread 类创建线程
2. 实现 Runnable 接口创建线程
2.Thread 和 Runnable的区别
Thread和Runnable的相同点:都是"多线程的实现方式”。
Thread和Runnable的不同点:Thread 是类,而Runnable是接口;Thread本身是实现了 Runnable 接口的类。我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性。此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。通常,建议通过“Runnable”实现多线程!
3.Thread和Runnable的多线程示例(暂不考虑数据竞态)
继承Thread创建步骤
1. 定义Thread类的子类,并重写该类的run()方法,该方法为线程执行体
2. 创建Thread子类的实例,也就是创建了线程对象
3. 启动线程,通过调用线程对象的start()方法来启动线程
Thread创建代码
package concurrent;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Description: 线程创建
* @Author: lizhouwei
* @CreateDate: 2018/5/20 16:17
* @Modify by:
* @ModifyDate:
*/
class MyThread extends Thread {
private AtomicInteger ticket = new AtomicInteger(10);
@Override
public void run() {
for (int i = 1; i <= ticket.intValue(); i++) {
System.out.println(Thread.currentThread().getName() + " ticket " + i);
}
}
}
public class ThreadDmo {
public static void main(String[] args) {
MyThread myThread1 = new MyThread();
myThread1.start();
}
}
实现Runnable创建步骤
1. 定义Runnable接口的实现类,重写run()方法,该方法为线程执行体
2. 创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象
3. 启动线程,通过调用线程对象的start()方法来启动线程
Runnable创建代码
package concurrent;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Description: 线程创建
* @Author: lizhouwei
* @CreateDate: 2018/5/20 16:17
* @Modify by:
* @ModifyDate:
*/
class MyRunnable implements Runnable {
private AtomicInteger ticket = new AtomicInteger(10);
public void run() {
for (int i = 1; i <= ticket.intValue(); i++) {
System.out.println(Thread.currentThread().getName() + " ticket " + i);
}
}
}
public class RunnableDmo {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread myThread = new Thread(myRunnable);
myThread.start();
}
}
4. start() 和 run()的区别
start():启动一个新线程,新线程会执行相应的run()方法。start()不能被重复调用(会抛出异常)。
run() :run()就和普通的成员方法一样,可以被重复调用。单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程!
2. start() 源码(by jdk1.8)
public synchronized void start() {
//判断状态是否为 New ;
if (threadStatus != 0)
throw new IllegalThreadStateException();
// 将线程添加到ThreadGroup中
group.add(this);
boolean started = false;
try {
// 通过start0()启动线程
start0();
// 设置started标记
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
5. 通过Thread的实例对象调用start()方法到底是怎么启动线程的?下面对其实现方式做一些简单的补充。
- 基于Kernel Thread(KLT)的映射来实现:KLT是内核线程,内核线程由OS直接完成调度切换,它相对应用程序的线程来讲只是一个接口,外部程序会使用一种轻量级进程(Light Weight Process,LWP)来与KLT进行一对一的接口调用。也就是说,进程内部会尝试利用OS的内核线程去参与实际的调度,而自己使用API调用作为中间桥梁与自己的程序进行交互。
- 基于用户线程(User Thread,UT)的实现:这种方式是考虑是否可以没有中间这一层映射,自己的线程直接由CPU来调度,或许理论上效率会更高。不过这样实现时,用户进程所需要关注的抽象层次会更低一些,跳过OS更加接近CPU,即自己要去做许多OS做的事情,自然的OS的调度算法、创建、销毁、上下文切换、挂起等都要自己来搞定(因为CPU只做计算)。这样做显然很麻烦,许多人曾经尝试过,后来放弃了。
- 混合实现方式:它的设计理念是希望保留Kernel线程原有架构,又想使用用户线程,轻量级进程依然与Kernel线程一一对应保持不变,唯一变化的就是轻量级进程不再与进程直接挂钩,而是与用户线程挂钩,用户线程并不一定必须与轻量级进程一一对应,而是多对多,就像在使用一个轻量级进程列表一样,这样增加了一层来解除轻量级进程与原进程之间的耦合,可能会使得调度更为灵活。
在以前的JDK版本中,尝试使用UT的方式来实现,但后来放弃了,采用了与Kernel线程对应的方式,至于一些细节,与具体的平台有很大的关系,JVM会适当考虑具体平台的因素去实现,在JVM规范中也没规定过必须如何去实现,所以对于程序员来讲,只需要知道在new Thread(),调用start()方法后,理论上就有一个可以被OS调度的线程了。
Java多线程系列 基础篇02 线程的创建和运行的更多相关文章
- Java多线程系列--“基础篇”02之 常用的实现多线程的两种方式
概要 本章,我们学习“常用的实现多线程的2种方式”:Thread 和 Runnable.之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多线程.关于线程 ...
- Java多线程系列 基础篇01 线程的状态
1.进程和线程 进程: 计算机中程序关于某数据集合的一次运行活动,是计算机系统进行资源分配和调度的基本单位,是操作系统结构的基础. 线程: 线程是进程的实例,是CPU进行资源分配和调度的最小单位,线程 ...
- Java多线程系列 基础篇03 线程的优先级和守护线程
1. 线程优先级 现代操作系统中基本上使用时间分片的方式调度线程,通过设置线程优先级,使优先级高的线程获得时间片的次数多于优先级低的线程. 在java 线程中,通过一个整形变量prority来控制优先 ...
- Java多线程系列 基础篇04 线程中断
1. 中断线程 中断可以理解为线程的一个标志位属性,它表示一个运行中的线程是否被其他线程进行了中断操作,其他线程通过调用该线程的interrupt()方法对其进行中断操作,线程通过检查自身是否被中断来 ...
- Java多线程系列--“基础篇”05之 线程等待与唤醒
概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. wait()和notify()3. wait(long t ...
- Java多线程系列--“基础篇”06之 线程让步
概要 本章,会对Thread中的线程让步方法yield()进行介绍.涉及到的内容包括:1. yield()介绍2. yield()示例3. yield() 与 wait()的比较 转载请注明出处:ht ...
- Java多线程系列--“基础篇”07之 线程休眠
概要 本章,会对Thread中sleep()方法进行介绍.涉及到的内容包括:1. sleep()介绍2. sleep()示例3. sleep() 与 wait()的比较 转载请注明出处:http:// ...
- Java多线程系列--“基础篇”09之 interrupt()和线程终止方式
概要 本章,会对线程的interrupt()中断和终止方式进行介绍.涉及到的内容包括:1. interrupt()说明2. 终止线程的方式2.1 终止处于“阻塞状态”的线程2.2 终止处于“运行状态” ...
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注明出处:http://www.cnblogs.com/skyw ...
随机推荐
- 最好PHP开发工具Zend Studio 9.0.2的安装和使用
摘要:Zend Studio是Zend Technologies开发的PHP语言集成开发环境(IDE),是公认最好的PHP开发工具.在5.5系列后,官方推出的Zend Studio都利用了Eclips ...
- 版本控制工具:SVN和Maven的区别
一.只有svn的情况 首先考虑没有maven的情况.这样的话,项目组每个开发人员,都需要在本地check out所有的源码. 每次提交之前,需要先更新周边工程的代码.由于工程之间是依赖的,所以很可能需 ...
- 传输层:TCP 协议
传输层:TCP 协议 一.概述 TCP 和 UDP 处在同一层——运输层,但是它们有很多的不同.TCP 是 TCP/IP 系列协议中最复杂的部分,它具有以下特点: (1) TCP 提供 可靠的 数据传 ...
- openTK学习
简介 the Open Tool Kit (OpenTK), 是对 OpenGL.OpenAL.OpenCL 的跨平台的封装,使用 C# 编写,它可以用在Mono.dotNet的语言:c#.VB.C+ ...
- 百度 api 测试 & python
''' 一.文字转语音api,树莓派天气闹钟爬取实时天气数据转换为语音,设置树莓派计划任务 ''' from aip import AipSpeech import requests import r ...
- HDU 3466 01背包变形
给出物品数量N和总钱数M 对于N个物品.每一个物品有其花费p[i], 特殊值q[i],价值v[i] q[i] 表示当手中剩余的钱数大于q[i]时,才干够买这个物品 首先对N个物品进行 q-p的排序,表 ...
- ES6 rest与扩展运算符
1.rest 变量将多余的参数放入数组中. function add(...values) { let sum = 0; for (var val of values) { sum += val; } ...
- SpringMVC:前台jsp页面和后台传值
前台jsp页面和后台传值的几种方式: 不用SpringMVC自带的标签 前台---->后台,通过表单传递数据(): 1.jsp页面代码如下, modelattribute 有没有都行 < ...
- Notepad2替换记事本--映像劫持
Image File Execution Options就是映像劫持技术,通过此种方式替换记事本,非常地绿色环保. Image File Execution Options是CreateProces ...
- 调试Scrapy过程中的心得体会
1.大量抓取网页时出现“Memory Error”解决办法:设置一个队列,每当爬虫空闲时才向队列中放入请求,例如: from scrapy import signals, Spider from sc ...