栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Java并发编程】进程(Process)、线程(Thread)、线程的串行、多线程原理、默认线程、开启新线程、多线程的内存布局、线程的状态、线程的状态切换、多线程的优缺点

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Java并发编程】进程(Process)、线程(Thread)、线程的串行、多线程原理、默认线程、开启新线程、多线程的内存布局、线程的状态、线程的状态切换、多线程的优缺点

九、并发编程

文章目录

九、并发编程

00_进程(Process)、线程(Thread)、线程的串行01_多线程原理、默认线程

多线程的原理多线程的优缺点默认线程 02_开启新线程

`Runnable``extends Thread` 03_多线程的内存布局04_线程的状态05_`sleep`、`interrupt`06_`join`、`isAlive`

00_进程(Process)、线程(Thread)、线程的串行

什么是进程?

在操作系统中运行的一个应用程序
比如同时打开 QQ 、微信,操作系统就会分别启动 2个进程

每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内在 Windows 中,可以通过“任务管理器”查看正在运行的进程

什么是线程?

1 个进程要想执行任务,必须得有线程(每 1 个进程至少要有 1 个线程)一个进程的所有任务都在线程中执行
比如使用酷狗播放音乐、使用迅雷下载文件,都需要在各自的线程中执行

线程的串行

1 个线程中任务的执行是串行的

如果要在 1 个线程中执行多个任务,那么只能一个一个地按顺序执行这些任务在同一时间内,1 个线程只能执行 1 个任务
比如在 1 个线程中下载 3 个文件(分别是文件 A、文件 B、文件 C)

01_多线程原理、默认线程

什么是多线程?

1 个进程中可以开启多线,所有线程可以并行(同时) 执行不同的任务
进程 → 车间
线程 → 车间工人多线程技术可以提高序的执行效率
比如同时开启 3 个线程分别下载 3 个文件 (分别是A、文件 B、文件 C)

多线程的原理

同一时间,CPU 的 1 个核心只能处理 1 个线程(只有 1 个线程在工作)多线程并发(同时)执行,其实是 CPU 快速地在多个线程之间调度(切换)

如果 CPU 调度线程的速度足够快,就造成了多线程并发执行的假象如果是多核 CPU,才是真正地实现了多个线程同时执行

思考:如果线程非常非常多,会发生什么情况?

CPU 会在 N 个线程之间调度,消耗大量的 CPU 资源,CPU 会累死每条线程被调度执行的频次会降低(线程的执行效率降低) 多线程的优缺点

优点:

能适当提高程序的执行效率能适当提高资源利用率(CPU、内存利用率)

缺点:

开启线程需要占用一定的内存空间,如果开启大量的线程,会占用大量的内存空间,降低程序的性能

线程越多,CPU 在调度线程上的开销就越大

程序设计更加复杂
比如线程之间的通信问题、多线程的数据共享问题

默认线程

每一个 Java 程序启动后,会默认开启一个线程,称为主线程(main 方法所在的线程)

每一个线程都是一个java.lang.Thread对象
可以通过Thread.currentThread方法获取当前的线程对象

public static void main(String[] args) {
	// Thread[main,5,main]
	System.out.println(Thread.currentThread());
}

根据Java源码可知,打印出来的Thread[main,5,main]表示:

进程名为main进程优先级为5进程组的名字为main

02_开启新线程 Runnable
public static void main(String[] args) {
	Thread thread = new Thread(new Runnable() {
		@Override
		public void run() {
			// 打印线程名
			System.out.println("开启了新线程:" + Thread.currentThread().getName());
		}
	});
	thread.setName("线程666"); // 设置线程名
	thread.start(); // Thread调用start方法之后,内部会调用run方法
}
开启了新线程:线程666

可以用 Lambda 表达式改写:

public static void main(String[] args) {
	Thread thread = new Thread(() -> { // lambda 表达式
		System.out.println("开启了新线程:" + Thread.currentThread().getName());
	});
	// 不设置线程名则会自动命名, Thread-0, Thread-1, ...
	thread.start(); // Thread调用start方法之后,内部会调用run方法
}
开启了新线程:Thread-0
extends Thread

Thread 类实现了 Runnable 接口

创建一个类 MyThread 继承 Thread 类:

public class MyThread extends Thread {
	@Override
	public void run() {
		System.out.println("开启了新线程:" + Thread.currentThread().getName());
	}
}
public static void main(String[] args) {
	Thread thread = new MyThread();
	thread.start();
}
开启了新线程:Thread-0

注:

直接调用线程的 run 方法并不能开启新线程调用线程的 start 方法才能成功开启新线程 03_多线程的内存布局

PC 寄存器(Program Counter Register)
每一个线程都有自己的 PC 寄存器

Java 虚拟机栈(Java Virtual Machine Stack):
每一个线程都有自己的 Java 虚拟机栈

堆(Heap)
多个线程共享堆

方法区(Method Area)
多个线程共享方法区

本地方法栈(Native Method Stack)
每一个线程都有自己的本地方法栈

04_线程的状态

可以通过Thread.getState方法获得线程的状态(线程一共有 6 种状态)

NEW(新建):尚未启动

RUNNABLE(可运行状态):正在JVM中运行
或者正在等待操作系统的其他资源(比如处理器)

BLOKCED(阻塞状态):正在等待监视器锁(内部锁)

WAITING(等待状态):在等待另一个线程

调用以下方法会处于等待状态

没有超时值的 Object.wait没有超时值的 Thread.joinLockSupport.park

TIMED_WAITING(定时等待状态)
调用以下方法会处于定时等待状态

Thread.sleep有超时值的 Object.wait有超时值的 Thread.joinLockSupport.parkNanosLockSupport.parkUntil

TERMINATED(终止状态):已经执行完毕

线程的状态切换:

05_sleep、interrupt

可以通过 Thread.sleep 方法暂停当前线程,进入WAITING状态;

在暂停期间,若调用线程对象的 interrupt 方法中断线程,会抛出 java.lang.InterruptedException 异常

public static void main(String[] args)  {
	Thread thread = new Thread(() -> {
		try {
			Thread.sleep(3000); // 睡眠3s
		} catch (InterruptedException e) { // 捕捉到异常则输出
			System.out.println("interrupt");
		}
		System.out.println("end");
	});
	thread.start();
	try {
		Thread.sleep(1000);
	} catch (InterruptedException e) {} // 捕捉到异常什么也不做
	thread.interrupt();
}
interrupt
end
06_join、isAlive

A.join 方法:等线程 A 执行完毕后,当前线程再继续执行任务。可以传参指定最长等待时间。
A.isAlive 方法:查看线程 A 是否还活着

public static void main(String[] args) {
	Thread t1 = new Thread(() -> {
	System.out.println("t1 - begin");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("t1 - end");
	});
	t1.start();

	Thread t2 = new Thread(() -> {
		System.out.println("t2 - begin");
		System.out.println("t1.isAlive - " + t1.isAlive());
		try {
			t1.join(); // 等待t1执行完成再继续往下执行
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("t1.state - " + t1.getState());
		System.out.println("t1.isAlive - " + t1.isAlive());
		System.out.println("t2 - end");
	});
	t2.start();
}
t1 - begin
t2 - begin
t1.isAlive - true
t1 - end
t1.state - TERMINATED
t1.isAlive - false
t2 - end

对比一下这两段代码细微的区别,t1.join(1000);

public static void main(String[] args) {
	Thread t1 = new Thread(() -> {
		System.out.println("t1 - begin");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("t1 - end");
	});
	t1.start();

	Thread t2 = new Thread(() -> {
		System.out.println("t2 - begin");
		System.out.println("t1.isAlive - " + t1.isAlive());
		try {
			t1.join(1000); // 等待t1 1s,但是t1 睡了2s,1s过去后t1 还没运行完
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("t1.state - " + t1.getState());
		System.out.println("t1.isAlive - " + t1.isAlive());
		System.out.println("t2 - end");
	});
	t2.start();
}
t1 - begin
t2 - begin
t1.isAlive - true
t1.state - TIMED_WAITING
t1.isAlive - true
t2 - end
t1 - end
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/768459.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号