并发编程初探
Java天生的多线程
当前的main函数就是一个JVM进程,在IDEA中可以看到共有6条线程
查看线程信息:jps(拿到线程的tid) + jstack(查看线程日志)
prio是进程中的优先级,os_prio是操作系统给线程定义的优先级,prio前加上deamo则为守护线程
-
[6] Monitor Ctrl-Break (跟JVM 关系不大,他是 IDEA 通过反射的方式,开启一个随着我们运行的jvm进程开启与关闭的一个监听线程。)
daemon prio=5 (可延迟开启)
-
**[5] Attach Listener **(附加监听器。 简单来说,他是jdk里边一个工具类提供的jvm 进程之间通信的工具。 cmd – java -version; jvm – jstack、jmap、dump) 进程间的通信。
daemon prio=5 (可延迟开启)
开启我们这个线程的两个方式: 1. 通过jvm参数开启。-XX: StartAttachListener延迟开启: cmd – java -version –> JVM 适时开启A L 线程
-
[4] Signal Dispatcher (信号分发器。 我们通过cmd 发送jstack,传到了jvm进程,这时候信号分发器就要发挥作用了。)
daemon prio=9
-
[3] Finalizer JVM 垃圾回收相关的内容。
- daemon prio=10 高优先级的守护线程。
- 只有当开始一轮垃圾收集的时候,才会开始调用finalize方法。
- jvm在垃圾收集的时候,会将失去引用的对象封装到我们的 Fianlizer 对象(Reference), 放入我们的 F-queue 队列中。由 Finalizer 线程执行inalize方法
- Finalizer 专注垃圾收集,垃圾收集 – 并行收集,不阻碍用户线程,低优先级线程。 prio=8 他是一个守护线程啊。而且这个线程目前并没有真正的开启,不足以发生minorgc或者是 full gc
-
[2] Reference Handler (引用处理的线程。强,软,弱,虚。 -GC 有不同表现 - JVM深入分析)
引用处理线程-GC相关线程
daemon prio=10(GC很重要,优先级较高)
-
[1] main 主线程
prio=5
操作系统面向的是JVM 进程,JVM 进程里面向的是 我们的main函数,。所以对于我们的操作系统如何看待我们的main函数优先级,无所谓。 只要os 给我们jvm进程足够公平的优先级就行。
线程的状态
注:上图的
Obejct.join()
应为Thread.join()
Thread.Sleep() 和 Object.Wait()
Thread.Sleep()
- 不释放锁
- 响应中断(对中断敏感)
- 会释放CPU
Obeject.wait()
- 会释放锁
- 响应中断(对中断敏感)
- 会释放CPU,让出时间片并进入等待队列
注:wait(0)表示永久等待
Thread.join()
底层调用Object.Wait()
-
会释放锁
-
Thread的join方法,释放的是当前调用 join方法的那个对象的锁。
-
1 2 3 4 5 6
synchronized (obj){ thread.join();//不释放锁 } synchronized (Thread.currentThread){ thread.join();//释放锁 }
-
-
响应中断(对中断敏感)
线程间的通讯方式
-
volitate 、synchronize、lock。(都保证可见性)
-
wait、notify、await() 、 signal
-
管道输入、输出流**(已过时)**
管道输入/输出流和普通的文件输入/输出流或者网络输入/输出流不同之处在于,它主要用于线程之间的数据传输,而传输的媒介为内存。管道输入/输出流主要包括了如下4种具体实现:PipedOutputStream、PipedInputStream、PipedReader和PipedWriter,前两种面向字节,而后两种面向字符。
-
Thread.join() : 隐式唤醒。等待其他线程执行完成,其他线程会发送唤醒信号。
-
ThradLocal():支持子线程集成的一种形式。
-
线程中断
线程中断时,sleep()会先清理中断标记,再抛出异常,导致thread.interupted = flase