Files
Hui-s-notebook/并发编程线程基础.md
2023-09-10 10:50:53 +08:00

3.5 KiB
Raw Permalink Blame History

v## 什么是线程

线程是进程中打一个实体,线程是进程的一个执行路径

线程创建与运行

集成 Thread 类

实现 Runnable 接口 run 方法

使用 FutureTask 方式,实现 Callable 接口 call 方法,使用 get 方法获取返回值

线程等待与通知

1 . wait 函数

当一个线程调用一个共享变量的 wait 方法时,该调用线程会被阻塞挂起,直到发生以下事件

  1. 其他线程调用了该共享对象的 notify 或 notifyAll
  2. 其他线程调用了该线程的 interrupt 方法,该线程抛出 InterruptedException 异常返回

如果调用该方法的线程没有获取该对象的监视器的监视器锁,调用时该线程会抛出 IllegalMonitorStateException 异常

如何获取一个共享变量的监视器锁?

  1. 执行 synchronized 同步代码块时,使用该共享变量作为参数
  2. 调用该共享变量的方法,该方法是使用了 synchronized 方法修饰
synchronized (共享变量) {
	// doSomething
}
synchronized void add (int a int b) {
	// doSomething
}

当线程调用共享对象的 wait方法时当前线程只会释放当前共享对象的锁当前线程持有的其他共享对象的监视器锁并不会被释放

2. wait (long timeout) 函数

如果一个线程调用该方法挂起后没有在指定超时事件内调用 notify 方法,该函授会因超时返回

3. wait (long timeout int nanos) 函数

内部调用wait (long timeout) 函数

4. notify ()函数

调用后会唤醒调用 wait 方法后被挂起的线程, 唤醒线程不能马上从 wait 方法返回并执行,必须获取共享对象打监视器锁后才能返回

4. notifyAll()函数

唤醒所有该共享变量上由于调用 wait 方法而被挂起的线程

等待线程执行终止的join方法

join 方法是 Thread 类直接提供的, join 方法是无参且返回值为 void 的方法

让线程睡眠的 sleep 方法

调用 sleep 方法后,调用线程会暂时让出指定时间的执行权,但是监视器资源还是不让出

让出 CPU 执行权的 yield 方法

调用 yield 方法后,就是在暗示线程调度器请求让出自己的 cpu 使用,但是线程调度器可以无条件忽略这个暗示

sleep 方法与 yield 方法的区别

线程调用 sleep 方法会被阻塞挂起指定时间,这期间线程调度器不会去调度该线程, 调用 yield 方法时,线程只是让出自己的时间片,没有被阻塞挂起,处于就绪状态,线程调度器下一次调度时有可能调度到当前线程执行

线程中断

  • void interrupt ()方法,中断线程,设置中断标志为 true 继续执行
  • boolean isInterrupt ()方法,检测当前线程是否被中断
  • boolean interrupted () 方法,检测当前线程是否被中断,发现中断,清楚中断标记

线程上下文切换

线程死锁

  • 互斥条件
  • 请求并持有条件
  • 不可剥夺条件
  • 环路等待条件

守护线程与用户线程

main 函数所在线程为用户线程JVM 内部还有守护线程,如垃圾回收, 当最后一个非守护线程结束时JVM 正常退出,不管是否有守护线程未结束

ThreadLocal

创建了一个 ThreadLocal 变量后,访问这个变量的每个线程都会有一个这个变量的本地副本,多个线程笑操作时,访问的是自己本地内存里的变量

同一个 ThreadLocal 变量在父线程中设置后,在子线程中获取不到

InheritableThreadLocal让子线程可以访问父线程中设置的本地变量