zoukankan      html  css  js  c++  java
  • [Thread,Thread State]线程,线程状态

    线程

    线程 & 进程

    学过操作系统的基本都知道这个词。一开始出现的是进程,进程是操作系统中分时系统的一个基本运作单位。但是后来由于系统设计的升级,对进程又进行了划分,所以出现了线程。
    进程可以包含多个线程,至少一个。这样就出现了线程来执行用户需要执行的命令。
    区别总结一下:

    1. 进程是一段正在执行的程序,是资源分配的基本单元,而线程时CPU调度的基本单元。
    2. 进程间相互独立,进程与进程之间不能共享资源,一个进程至少有一个线程,同一个进程的各线程共享整个进程的资源(寄存器,堆栈,上下文)。
    3. 线程的创建和切换开销比进程小。

    JAVA中的线程

    高级语言都有一套使用线程的方法。在JAVA中最原始的方法就2种:

    1. 继承Thread
    2. 实现Runnable接口

    当然除了这里的最原始的方法,还有一些方法可以创建线程。

    线程的状态

    线程状态大致可以分为5种:

    1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
    2. 可运行(RUNNABLE):也称为就绪状态,调用start方法后线程就计入就绪状态但并不是说只要调用start方法线程就马上变为当前线程,在变为当前线程之前都是就绪状态。线程在睡眠和挂起中恢复的时候也会进入就绪状态。线程对象创建后,其他的线程调用了它的start方法,这个线程就会进入可运行线程池中,等待被调度选中,获取CPU的使用权。
    3. 运行(RUNNING):可运行状态(RUNNABLE)的线程获得了CPU的时间片,执行程序代码,开始执行run
    4. 阻塞(BLOCKED):线程由于某种原因放弃了CPU的使用权,也就是时间片,暂时停止了运行。
      a. 等待阻塞: 通过调用线程的wait方法,让线程等待某工作的完成,线程进入等待队列(waitting queue)。
      b. 同步阻塞: 线程在获取synchronized失败,会进入同步阻塞状态,线程进入阻塞。
      c. 其他阻塞: 通过调用线程的sleep或者join或发出了I/O请求,线程会进入阻塞。当sleep超时,join等待线程终止或超时,或I/O完毕,线程就重新进入可运行状态(RUNNABLE)
    5. 死亡(DEAD):线程执行结束,run,main方法结束,或者因为异常退出了run,该线程结束生命周期,状态不可逆转。

    当然在JDK中,线程的状态有NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED,和系统层面的划分差不多。

    1. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
    2. 限时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
    3. 终止(TERMINATED):表示该线程已经执行完毕。

    线程状态图

    初始状态:

    实现了Runnable接口或者继承了Thread的一个类,通过new创建了实例,线程就进入了初始状态。

    可运行状态:

    • 可运行状态只是代表该线程在随时等待调度程序。
    • 调用线程的Start方法,线程进入可运行状态。
    • 当前线程sleep结束,其他线程join结束,IO结束,拿到了对象锁,线程也可以进入可运行状态。
    • 当前线程时间片用完后,调用了该线程的yield方法,该线程进入可运行状态。

    运行状态:

    进入运行状态RUNNING,只有等到被调度程序选中,才能够进入。

    死亡状态:

    • 当线程run完成时,或者main方法完成,就认为dead。
    • 如果尝试在一个dead的线程上start,会抛出IllegalThreadStateException

    阻塞状态:

    • 当前线程调用了sleep方法,当前线程进入阻塞。
    • 运行在当前线程里的其他线程调用了join方法,当前线程进入阻塞
    • 等待IO时,当前线程进入阻塞。

    有很多的博客,提到了一些锁池,等待队列,等待池,可运行池的概念,但是我一直没有找到这些名词的来源,没有哪本书中,提过这些名词。但是通过这些名词,解释了一些可能不容易理解的问题。
    从一个国外站上面看到一个文章说是这样解释的:
    Inside the Java Virtual Machine

    在JAVA中,每个对象都有一个内部锁(Monitor)。JVM会为每个对象维护2个区域,Entry Set(入口集),Wait Set(等待集)。Entry Set存储了等待获取object的内部锁的所有线程,Wait Set存储了执行了object.wait方法的线程。

    如果有个线程A执行了wait,那么A就会被暂停,状态变为WAITTING,进入Wait Set,我们可以称A为object的等待线程,当其他线程执行了object.notify或者notifyAll,Wait Set中的任意一个线程会被唤醒进入RUNNABLE,并且会参与和Entry Set中的线程一起争夺monitor。如果wait set的线程成功拿到了锁,这个线程就可以从Wait Set移除,否则该线程还会留在Wait set,并且再次暂停,等待下次申请锁的机会。

    线程的方法

    Thread.Sleep(long millis)

    sleep属于线程的方法,调用后当前线程进入阻塞,但是不会释放锁,millis之后,线程会苏醒进入可运行状态RUNNABLE

    Thread.yield()

    当前线程调用该方法,当前的线程就会放弃CPU,由RUNNING-->RUNNABLE,让相同优先级的线程轮流执行,但是不一定保证实际会轮流执行。当然该线程也有可能会被调度程序再次选中,yield不会导致阻塞。

    t.join/t.join(long millis)

    当前线程t1里调用其他线程t2的join方法,当前线程实际进入wait ,直到t2执行完毕或者join时间到了,t1被可能唤醒进入可运行状态。

    object.wait()

    当前线程调用object的wait方法,当前线程释放对象锁,只能等notify,notifyall唤醒或者wait时间到唤醒。

    object.notify

    唤醒在这个对象锁上面的某一个线程,notifyAll唤醒这个对象锁上面的所有线程。

  • 相关阅读:
    hive sql 解析json
    解决华为手机无法安装未签名apk问题(该安装包未包含任何证书)
    对马尔科夫决策过程的代码补充解释
    对马尔科夫决策过程MDP(Markov Decision Processes)的一点理解
    使用Web在PC和安卓之间传输文件(Transfer files via wifi)
    记录下自己的生活状态,昏昏沉沉的半年,迷茫的未来
    __repr__和pass在python中的含义
    LaTeX基础调节,调节行距,字体大小,字体,页边距
    LaTeX怎么让一行中的一部分右对齐
    Tkinter主动刷新(强制刷新)
  • 原文地址:https://www.cnblogs.com/dreamtaker/p/13608982.html
Copyright © 2011-2022 走看看