1 线程的生命周期
阻塞block:仅sychronized,ReetrentLock只会导致线程等待
2 线程的调度
协同式线程调度:线程执行的时间由线程本身来控制,线程把自己的工作执行完之后,要主动通知系统切换到另外一个线程上
抢占式线程调度:每个线程执行的时间以及是否切换都由系统决定;在这种情况下,线程的执行时间不可控
java为什么是抢占式线程调度?
用户线程操作比较麻烦,采用内核线程实现,由OS管理的抢占式线程调度
3 线程和协程
一台机器能同时运行的线程数:2000个
3.1 内核线程实现(1:1)
线程操作,如创建、析构及同步,都需要进行系统调用
系统调用的代价相对较高, 需要在用户态(User Mode)和内核态(Kernel Mode)中来回切换
3.2 用户线程实现(1:N)
非常快速且低消耗
用户线程的建立、同步、销毁和调度完全在用户态中完成,不需要内核的帮助
3.3 混合实现(N:M)
多个用户级线程与某个内核线程对应;期间的映射也是很复杂的
3.4 Java线程的实现
采用 1: 1 的线程模型
JVM无法干预CPU调度(抢占式调度)
Java线程中设置的优先级不太好映射
3.5 协程
适用于IO密集型(磁盘IO、网络IO)【在规模上得到增强,在计算上比一般线程慢】
市面上JVM多采用1:1 的内核线程模型,tomcat、微服务等要求必须在极短的时间内完成计算,若都采用内核线程,则耗时严重,用户线程的重新引入成为必然
最初多数的用户线程是被设计成协同式调度的,所以它有了一个别名——“协程”
3.6 守护线程
通过调用 Thread.setDaemon(true)将线程设置为 Daemon 线程,比如垃圾回收线程就是 Daemon 线程
Java执行main方法时,同时会启用5个守护线程
随着主线程终止而结束,是随时可能结束(不适合文件清理、解锁、回收)
4 线程间的通信
4.1 管道输入输出流
利用Java生成excel文件,从DB中读取数据到内存中,生成文件再上传(利用管道输入输出流可以不在内存中生成文件,直接上传)
Java 中的管道输入/输出流主要包括了如下 4 种具体实现:
字节流:PipedOutputStream、PipedInputStream
字符流:PipedReader 和 PipedWriter
5 join方法
现在有 T1、T2、T3 三个线程,你怎样保证 T2 在 T1 执行完后执行,T3 在 T2执行完后执行?
答:用 Thread#join 方法即可,在 T3 中调用 T2.join,在 T2 中调用 T1.join