目录
1.多线程简介
1.多任务与多线程的初步了解
多任务
现实中太多这样同时做多件事情的例子了,看起来是多个任务都在做,其实本质上我们
的大脑在同一时间依旧只做了一件事情。例:吃饭玩手机,上厕所玩手机多线程
原来是一条路,慢慢因为车太多了,道路堵塞,效率极低。
为了提高使用的效率,能够充分利用道路,于是加了多个车道。
从此,妈妈再也不用担心道路堵塞了。
2.普通方法的调用与多线程
3.程序.进程.线程
一个进程可以有多个线程,形成一个程序
如:视频中同时听声音、看图像、看字幕等等
Process(进程)与Thread(线程)
◆说起进程,就不得不说下程序。程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
◆而进程则是执行程序的一次执行过程,它是一个动态的概念。 是系统资源分配的单位应用程序(typerpa,word,IDEA)运行的时候进入到内存,程序在内存中占用的内存空间叫做进程。
◆通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的的单位。程序中如果只有一条执行路径,那么这个程序就是单线程的程序
多线程是指从软硬件上实现多条执行流程的技术。
注意:很多 多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务
器。如果是模拟出来的多线程,即在一个cpu的情况下, 在同一个时间点,cpu只能
执行一个代码,因为切换的很快,所以就有同时执行的错局。补充知识点:人间一天(s),计算机十年(ns)
4.多线程核心概念
- 线程就是独立的执行路径
- 在程序运行时,即使没有自己创建线程,后台也会有多个线程,比如主线程,GC线程
- main()称之为主线程,为系统的入口,用于执行整个程序
- 在一个进程中,如果开辟了多个线程,线程的运行是由调度器安排调度的,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的
- 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
- 线程会带来额外的开销,如CPU调度时间,并发控制开销
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
5.并发与并行
正在运行的程序(软件)就是一个独立的进程, 线程是属于进程的,多个线程其实是并发与并行同时进行的
并发:
CPU同时处理线程的数量有限。
CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,这就是并发。
并行:
在同一个时刻上,同时有多个线程在被CPU处理并执行。
并发性
多个线程操作同一资源
同一对象被多个线程操作
例:上万人抢100张票、两个银行同时取钱
6.线程同步与异步
同步:形容一次方法调用,同步一旦开始,调用者必须等待该方法返回,才能继续
单条执行路径:单线程
异步:形容一次方法调用,一旦开始,像是一次消息传递,调用者告知之后立即返回。二者竞争时间片,并发执行
多条执行路径:多线程
2.线程实现
三种创建方式
Thread class继承Thread类(重点)
Runnable接口 实现Runnable接口(重点)
Callable接口 实现Callable接口(了解)
直接调用run方法会当成普通方法执行,此时相当于还是单线程执行。
只有调用start方法才是启动一个新的线程执行
方式 | 优点 | 缺点 |
---|---|---|
继承Thread类 | 编程简单,可以直接使用Thread类中的方法 | 扩展性较差,不能再继续继承其他的类,不能返回线程执行的结果 |
实现Runnable接口 | 扩展性强,实现该接口的同时还可以继承其他的类 | 变成相对复杂,不能返回线程执行的结果 |
实现Callable接口 | 扩展性强,实现该接口的同时还可以继承其他的类,可以的到线程执行的结果 | 编程相对复杂 |
1.Thread类
Thread类是线程对象的描述类
自定义线程类继承Thread类
重写run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
线程不一定立即执行,CPU安排调度
优缺点:
优点:编码简单
缺点:线程类已经继承Thread,无法继承其他类,不利于扩展。
package java_se.java_jinjie.duoxiancheng.demo01;
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
//总结:注意,线程开启不一定立即执行,由CPU调度执行
public class Demo1 extends Thread{
@Override
public void run() {
//run()方法线程体
for (int i = 0; i < 2; i++) {
System.out.println("我在看代码---+i" +i);
}
}
public static void main(String[] args) {
//main线程,主线程
//创建一个线程对象
Demo1 demo1 = new Demo1();
//调用start()方法
demo1.start();
for (int i = 0; i < 20; i++) {
System.out.println("我在学习多线程---"+i);
}
}
}
获取和修改线程名称
- 获取线程ID和线程名称
- 1.在Thread的子类调用this.getId()或this.getName()
- 2.使用Thread.currentThread().getId()和Thread.currentThread().getName()
- 修改线程名称
- 1.调用线程对象的setName()方法
- 2.使用线程子类的有参构造方法赋值
不建议使用:避免OOP单继承局限性
package java_se.java_jinjie.duoxiancheng.demo01;
import org.jetbrains.annotations.NotNull;
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
//总结:注意,线程开启不一定立即执行,由CPU调度执行
public class Demo1 extends Thread{
@Override
public void run() {
//run()方法线程体 启动线程,不能run方法,使用start
for (int i = 0; i < 2; i++) {
// //第一种方式