线程状态转换

作者: 涵溢 | 来源:发表于2017-09-25 23:51 被阅读0次

线程是由内核自动调度的运行在进程上下文中的逻辑流。

基本概念

线程有自己的上下文:唯一的Thread ID、栈、栈指针、程序计数器、通用目的寄存器、条件码。

并发与并行
  • 并发:在单核多任务或者任务数大于核数的情况下,对于某个cpu来说,会把cpu执行时间分为几个时间片,交替运行任务。在一个时间片内执行某个任务后(可能没执行完),会挂起当前的任务然后执行其他的任务。挂起前会保留线程的上下文以便从中断点恢复cpu状态,例如:cpu寄存器(记录挂起前变量值等等),程序计数器(记录线程执行到哪条指令了)等等。

  • 并行:多核情况下,两个任务分别在不同cpu执行,两个任务互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

分类
  • 守护线程
    在操作系统中,是没有守护线程概念的,只有守护进程。jvm借鉴了unix守护进程的概念,构建了对自己有利的守护线程。有以下特点:

    • 为用户线程服务的
    • 优先级较低,只剩下守护线程的话,jvm就会退出
    • 典型的例子GC Daemon,当就剩下GC Daemon时,就没有垃圾产生,就没有存在的必要了,jvm就会退出
    • 在Daemon线程中产生的新线程也是Daemon的,而守护进程fork()出来的子进程不再是守护进程。
  • 用户线程:非守护线程

线程的状态

分类
  • 新建(New):准备线程执行需要的一些条件,例如线程自己的一些上下文

  • 就绪(Runnable):线程准备好的条件满足后进入就绪状态或者Running的时间片到了也会进入就绪状态

  • 运行 (Running):就绪状态的线程分配到了cpu时间片

  • 定时等待(Timed Waiting):时间内的等待

  • 等待(Waiting):主动睡眠,等待被唤醒

  • 阻塞(Blocked):IO阻塞或者等待锁

  • 终止(Terminated):死亡

线程运行中会被某些原因所打断进入阻塞(详细分为Timed Waiting,Waiting,Blocked)或者Runnable(时间片到了)

线程状态的转换
状态转换图
  • start()方法标识启动一个线程,并分配资源。
  • yield()交出时间分片让高优先级的线程先执行,如果持有锁的话是不会释放掉的。
  • sleep()方法会交出时间分片,如果持有锁的话是不会释放掉的。
  • Object.wait()交出cpu时间,并且释放掉锁。
  • 使用wait(),notify(),notifyAll()前先拿到锁后才能执行,因为方法或者代码块执行完才能释放锁,所以在方法里使用notify()或者notifyAll()后最好不要跟太耗cpu时间的计算。
  • new Object().wait() 编译不会报错,但运行会报java.lang.IllegalMonitorStateException
  • join()调用了Object.wait()方法。
  • interrupt()可以中断正在处于阻塞(Waiting,Timed Waiting,不包括Blocked)的线程,使阻塞线程抛出InterruptedException,sleep、wait、join这些方法都会抛出InterruptedException。 interrupt()会把中断标志位置为true。
  • interrupt()不可中断不处于阻塞的线程,但是interrupt()后如果用isInterrupted()来判断标志位(是否中断)也可以达到目的。
  • 有些操作是不适合用Daemon线程的,例如读写操作,因为在Daemon Thread还没来的及进行操作时,虚拟机可能已经退出了。
  • thread.setDaemon(true)必须在start()之前设置,否则会抛IllegalThreadStateException异常。

因为Thread类用了代理模式,实现了Runnable接口的run方法。
可以使用new Thread(被代理的Runnable实例).start(); 执行的是被代理类的run;
当然也可以直接继承Thread覆写run方法。

下篇详细剖析下JCU里的老大-AQS,请大家保持关注哦。

相关文章

网友评论

    本文标题:线程状态转换

    本文链接:https://www.haomeiwen.com/subject/hqulextx.html