「Java 路线」| 并发编程的基础概念

2021-01-02  本文已影响0人  彭旭锐

点赞关注,不再迷路,你的支持对我意义重大!

🔥 Hi,我是丑丑。本文 「Java 路线」| 导读 —— 他山之石,可以攻玉 已收录,这里有 Android 进阶成长路线笔记 & 博客,欢迎跟着彭丑丑一起成长。(联系方式在 GitHub)


前言


目录


1. 基本概念

1.1 进程与线程

1.2 CPU 与处理器

1.3 CPU 时间片轮转机制

时间片轮转机制(又称 Round-Robin,RR 调度),是用于分时系统的线程调度机制,要点如下:

易混淆: 线程的时间片分配是抢占式的,而线程间的工作是协作式的。

1.4 并行 & 并发

1.5 并发编程注意事项

OS限制:一个进程Linus最大线程1000 window最大线程2000
线程:栈空间(缺省1M)、文件描述符/句柄1024

Editting...


2. Java 中的线程

2.1 执行 main() 方法,会启动几个线程?

总所周知,main() 方法是 Java 程序的入口,运行在主线程(线程名:main)。事实上,除了主线程外,虚拟机同时还启动了其他子线程。我们可以通过以下代码打印运行的线程:

ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos =  threadMXBean.dumpAllThreads(false, false);
for(ThreadInfo threadInfo:threadInfos) {
    System.out.println("["+threadInfo.getThreadId()+"]"+" " +threadInfo.getThreadName());
}

输出如下:

线程 作用
[1] main 主线程
[2] Reference Handler 清除 Reference
[3] Finalizer 调用 finalize() 方法
[4] Signal Dispatcher 分发处理发送给 JVM 信号
[5] Attach Listener 内存 dump,线程 dump,类信息统计,获取系统属性等
[6] Monitor Ctrl-Break 监控 Ctrl-Break 中断信号

2.2 启动线程的方式

提示: 启动线程的方式有人认为有两种,有人认为有三种。建议不必纠结于结论,关注是否自圆其说即可。

根据 JDK 官方在java.lang.Thread.java 中的注释,存在 两种启动线程 的方式:

There are two ways to create a new thread of execution. One is to declare a class to be a subclass of Thread.
...
The other way to create a thread is to declare a class that implements the Runnable interface. That class then implements the run method. An instance of the class can then be allocated, passed as an argument when creating Thread, and started.

有的说法会将java.util.concurrent.Callable也列为一种启动方式,其实 Callable 只是 java.util.concurrent.FutureTask的任务接口,而 FutureTask 本身就是 Runnable 的子类,所以「两种方式」的说法更有说服力。

FutureTask<V> ->RunnableFuture<V> -> Runnable

Thread 和 Runnable 的区别

Thread 是 Java 线程的抽象,Runnable 是对任务的抽象,与线程没有直接关系。Thread 可以接受任意一个 Runnable 的实例并执行。

start() 和 run() 的区别

start() 是启动一个线程,让一个线程进入「就绪状态」等待分配 CPU 时间片,分到时间片后执行 run() 方法,start() 方法重复执行会抛出异常;而 run() 方法是承载业务逻辑的地方,本质上是一个普通的实例方法,可以重复执行。

2.3 线程终止的方式

Thread#run()执行结束,或者执行过程抛出了未捕获的异常,则线程 自然终止。

线程停止、暂停和恢复分别对应suspend () & resume() & stop(),需要注意的是,这些 API 都是 过时的

中断本质上不属于终止线程的方式,但是往往 中断会给予线程终止的时机。例如在sleep() 、wait()等方法上阻塞的线程,就可以利用中断来退出等待,进而判断是否应该终止线程的业务逻辑。关于中断的具体介绍,见「Java 路线」| 线程协作机制

提示: 可以响应中断的方法往往声明throws InterruptedException


3. 线程优先级

Edigging...


4. 守护线程

4.1 定义

守护(Daemon)线程是一种支持型线程,当虚拟机中所有非守护线程都终止时,虚拟机就会退出,不理会守护线程是否终止。

例如 第 2.1 节 中提到的 Reference Handler 线程和 Finalizer 线程就是守护线程。通过Thead#setDaemon(true)可以设置守护线程,

4.2 finally{} 块一定会执行吗?

一般来说,try-catch-finally 代码块中 finally 块是一定会执行的,除了以下特殊情况,finally{} 块不一定会执行


掌握了并发编程的基本概念,下面我们就可以愉快地深入交流了,所有精彩内容尽在: 「Java 路线」| 导读 —— 他山之石,可以攻玉 ,常来玩~


创作不易,你的「三连」是丑丑最大的动力,我们下次见!

上一篇 下一篇

猜你喜欢

热点阅读