JUC(入门1-3章)

  • 进程线程
    进程是资源调度的基本单位
    线程是cpu调度的基本单位
    一个进程可以包含一个或多个线程,共享进程资源
  • 并行并发
    concurrent:并发
    真正同时运行(多cpu):并行
    时间片轮转运行(但cpu):并发
    并发:是同一时间应对多件事情的能力
    并行:是同一时间动手做多件事情的能力
  • 同步异步
    需要等待结果返回,才能继续运行就是同步
    不需要等待结果返回,就能继续运行就是异步

JMH性能测试工具

  • 线程创建
    • 继承Thread类,重写run方法
    • 传实现Runnable接口对象,执行Runnable的run方法(与Thread类解耦,任务与类分开)
    • 传FutureTask对象(对象创建时需要传入实现Callable接口的对象),处理有返回值情况

查看进程线程方法

windows:

  • 任务管理器
  • tasklist查看进程
  • taskkill杀死进程

linux:

  • ps -fe查看所有进程
  • ps -fT -p <PID> 查看某个进程的所有线程
  • kill 杀死进程
  • top按大写H切换是否显示线程
  • top -H -p <PID>查看某个进程的所有线程

java

  • jps查看所有java进程
  • jstack <PID> 参看某个java进程的所有线程状态
  • jconsole查看某个java进程中线程的运行情况(图形界面)

线程上下文切换

  • 线程的cpu时间片用完
  • GC
  • 有更高优先级的线程需要运行
  • 线程自己调用了sleep、yield、wait、join、park、synchronized、lock等方法

常见方法

start():启动一个新线程(进入就绪列表,不能多次调用)

run():新线程启动后会调用这个方法(还是父线程执行)

join():等待线程运行结束

join(long n):等待线程结束,最多等待n毫秒

getId():获取线程id

getName(String):获取线程名

getPriority():获取线程优先级

setPriority(int):设置线程优先级

getState():获取线程状态

isInterrupted():是否被打断

isAlive():是否存活

interrupt():打断线程(把休眠的线程叫醒)

currentThread():获取当前正在执行线程(static)

sleep(long n):休眠线程n毫秒(static)

yield():提示线程调度器让出当前线程对CPU的使用(static)

sleep与yield

sleep

  • 调用sleep会让当前线程进入TimedWaiting状态
  • 其他线程可以使用interrupt方法打断正在睡眠的线程,此时sleep方法会抛出InterruptedException
  • 休眠结束后的线程未必立刻得到执行
  • 建议用TimeUnit的sleep代替Thread的sleep来获得更好的可读性
    TimeUnit.SECONDS.sleep(long time)

yield

  • 调用yield会让当前线程从Running进入Running就绪状态,然后调度执行其他线程
  • 具体实现依赖OS的任务调度器

线程优先级

  • 线程优先级会提示调度器有限调度该线程,但它仅仅是一个提示,调度器可以忽略它
  • 如果cpu比较忙,那么优先级高的线程会获得更多的时间片,但空闲时,优先级几乎没有什么作用

防止CPU占用100%

  • 使用sleep,给其他线程使用CPU的时间
  • 可以使用wait或变量条件达到类似的效果
  • 不同的是,后两种都需要加锁,并且需要相应的唤醒操作,一般适用于要进行同步的场景
  • sleep适用于无需锁同步的场景

sleep、wait、join抛出异常的同时,中断标记位会被自动清除(变回 false)

两阶段终止模式

错误思路:stop(无法释放共享资源)、System.exit(int)(停止整个进程)

使用interrupt和isInterrupt实现

interrupted() 返回打断标记并清除(static)

而isInterrupt不会清除

打断park线程

LockSupport.park()

打断后不会抛出异常,并且将打断标记设置为true

注意之后park会无效(可以用Thread.interrupted()方法将打断标记设置为false)

不推荐使用的方法

stop() :停止线程运行 (使用二阶段终止模式)

suspend(): 挂起(暂停)线程运行(wait方法,会释放锁)

resume():恢复线程运行(notify唤醒)

原因:它们绕过了线程同步机制,直接粗暴控制线程生命周期

主线程与守护线程

默认情况下,java进程需要等待所有线程都运行结束,才会结束,有一种特殊的线程叫守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束

例子:

垃圾回收线程(当程序停止,垃圾回收线程也会停止)

线程五种状态

从操作系统层面描述

  • 初始状态:仅是在语言层面创建了线程对象,还未与操作系统线程关联
  • 可运行状态:指该线程已经创建(与操作系统线程关联),可以由CPU调度执行
  • 运行状态:指获取了CPU时间片运行中的状态
  • 阻塞状态:
    • 如调用了阻塞API,如BIO读写文件,这时该线程实际不会用到CPU,会导致线程上下文切换,进入阻塞状态
    • 等BIO操作执行完毕,会由操作系统唤醒阻塞线程,转换至可运行状态
  • 终止状态:表示线程已经执行完毕,生命周期已结束

线程六种状态

从java api层面描述的

根据Thread State枚举,分为六种状态

  • new:线程刚刚创建,未调用start方法
  • Runnable:包含os层面的可运行状态、运行状态、阻塞状态
  • terminated:终止状态
  • blocked:竞争锁失败(阻塞)
  • waiting:如join
  • timed_waiting:如sleep
相关推荐
LJianK12 小时前
Java中的类、普通类,抽象类,接口的区别
java·开发语言
LiLiYuan.3 小时前
【Java线程 vs 虚拟机线程】
java·开发语言
2402_881319303 小时前
跨服务通信兜底机制-Java 回传失败无持久重试队列,报告可能静默丢失。
java·开发语言·python
明灯伴古佛3 小时前
面试:对Spring AOP的理解
java·spring·面试
Nyarlathotep01133 小时前
ConcurrentHashMap源码分析
java·后端
Barkamin4 小时前
多线程简单介绍
java·开发语言·jvm
小比特_蓝光4 小时前
算法篇二----二分查找
java·数据结构·算法
田梓燊4 小时前
leetcode 56
java·算法·leetcode
scan7244 小时前
龙虾读取session历史消息
java·前端·数据库