线程基础知识复习
java8 API文档 https://www.matools.com/api/java8
涉及到并发的包
并发始祖
多线程的好处
- 提高程序性能,高并发系统
- 提高程序吞吐量,异步+回调等生产需求
多线程的弊端
- 线程安全性问题
- 线程锁问题
- 线程性能问题
start线程解读
Thread thread = new Thread(() -> {
}, "t1");
thread.start();
进入到 start 方法中可以看到下图,可以看到在其中调用到了 start0()
这个方法。
\
在进入 start0()
发放中,可以看到是使用 native 修饰的方法,就证明了是调用的 JNI 本地接口调用,调用的是第三方C语言所编写的底层函数或者操作系统代码。java语言本身底层就是 C++ 语言。
private native void start0();
建议下载 jdk8 源码到本地观看:https://hg.openjdk.java.net/jdk8
thread.c
- java线程是通过start的方法启动执行的,主要内容在native方法start0中,openjdk的写JNI一般是一一对应的,Thread,java对应的就是Thread.c
start0
其实就是JVM StatThread
。此时查看源代码可以看到在jvm.h中找到了声明,jvm.cpp中有实现。thread.c
文件位置:\openjdk8\jdk\src\share\native\java\lang
jvm.cpp
- 下图中可以看到 对应的
JVM StatThread
方法中 最下面去调用了 start方法传入了一个本地线程 jvm.cpp
文件位置:\openjdk8\hotspot\src\share\vm\prims
thread.cpp
- 调用了操作系统的线程启动,os::start_thread(thread);
thread.cpp
文件位置:\openjdk8\hotspot\src\share\vm\runtime
总结
通过上述不走可以看到 start0() 方法是通过 jvm 和 操作系统配合分配了一个原生的基础线程
Java多线程相关概念
把锁
个并
并发(concurrent)
是在同一实体上的多个事件是在一台处理器上“同时”处理多个任务同一时刻,其实是只有一个事件在发生
并行(parallel)
是在不同实体上的多个事件,是在多台处理器上同时处理多个任务,同一时刻,大家都真的在做事情,你做你的,我做我的
并发 VS 并行
个程
进程
系统中运行的一个应用程序就是一个进程,每一个进程都有它自己的内存空间和系统资源。
线程
也被称为轻量级进程,在同一个进程内基本会有1一个或多个线程,是大多数操作系统进行调度的基本单元。
管程
Monitor(监视器),也就是我们平时说的锁
Monitor其实是一种同步机制,他的义务是保证(同一时间)只有一个线程可以访问被保护的数据和代码。
JVM中同步是基于进入和退出监视器对象(Monitor,管程对象)来实现的,每个对象实例都会有一个Monitor对象,
Monitor对象会和Java对象一同创建并销毁,它底层是由C++语言来实现的。
用户线程和守护线程
Java线程分为用户线程和守护线程,不做配置的话默认就是用户线程
用户线程
是系统的工作线程,它会完成这个程序需要完成的业务操作
守护线程
是一种特殊的线程,为其他线程服务的,在后台默默地完成一些系统性的服务,比如垃圾回收线程。
用户线程操作案列
public static void main(String[] args) {
Thread thread = new Thread(() -> {
// Thread.currentThread().isDaemon() 判断是否是守护线程
System.out.println(Thread.currentThread().getName() + "\t 开始运行:" +
(Thread.currentThread().isDaemon() ? "守护线程" : "用户线程"));
// 死循环目的是为了测试 用户线程和守护线程结果
while (true) {
}
}, "t1");
thread.start();
// 3秒钟后主线程再运行
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("main 线程运行完毕");
}
用户线程运行结果
我们看到了默认是用户线程,是独立的主程序结束了但是用户线程还是运行,所以程序未终止。
守护线程操作案列
// 设置为守护线程
thread.setDaemon(true);
守护线程运行结果
可以看到程序终止了,因为守护线程是为其他线程服务的,其他线程关闭了默认也就关闭了
注意
- 守护线程作为一个服务线程,没有服务对象就没有必要继续运行了,如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可退出了。假如当系统只剩下守护线程的时候,java虚拟机会自动退出。
- setDaemon(true)方法必须在start()之前设置,否则报IIIegalThreadStateException异常