线程有哪些状态,对于这个问题,有些说五种,有些说六种。各有各的说法。我们一次来说明一下
- NEW: 新建
- RUNNABLE:可运行
- TERMINATED:终止
- BLOCKED:阻塞
- WAITING:等待
- TIMED_WAITING:有时限的等待
我们来分别细细说说每种状态的产生,和他们之间的转换
NEW -> RUNNBALE -> TERMINATED
(new)新建状态,这时 只时单纯new了一个Thread对象,这时仅仅是Java对象,并没有跟操作系统底层的线程所关联,并不会被分配cpu。当调用线程的start方法是,就会由新建状态转为RUNNABLE状态,这时这个线程真正的关联了底层的线程,这时才会被cpu执行。当执行完run方法时,线程就会由RUNNABLE转为TERMINATED终止状态。 这三种状态 是顺时针进行的,不可逆转,也就是 不会由 TERMINATED变为RUNNABLE,RUNNABLE也不会变为NEW状态。
RUNNABEL <=> BlOCKED
什么时候会变为BLOCKED状态。当多个线程争抢同一把锁时,只有一个线程可以持有锁,而其他线程则由RUNNABLE变为BLOCKED。当持有锁的线程释放锁后,处于BLOCKED的线程去争抢锁,争抢到锁的由BLOCKED状态转为RUNNABLE状态。
RUNNABLE => WAITING = > BLOCKED
当线程在获取锁之后,执行过程中 发现有条件没有满足,不能往下执行,这时不能一直占着锁,所以使用wait()方法来讲锁释放,并由RUNNABLE状态转为WAITING状态。 当其他线程调用notify()或者notifyAll()的方法时,就会唤醒等待的线程,让WAITING状态的线程转为BLOCKED 重新去竞争锁。
RUNNABLE => TIMED_WAITING
第一种:当调用wait(long time) 有时间的方法时,会在时间到了或者被主动唤醒时再去争抢锁
第二种:通过sleep(long time)这种方式,可以不用放在锁内,即使放在锁内,也不会释放锁,当时间到的时候会重新变为RUNNABLE状态。
2.在操作系统层面的五种线程状态
1.新建。
2.就绪。
3.运行。
4.阻塞
5.终止
通过对比发现,操作系统层面 把RUNNABLE进行了再细分,把BLOCKED和WAITING和TIMED_WAITING 一起划分为了阻塞状态。但多了个io操作,也属于阻塞层面,这是为什么。是因为再进行io对磁盘的读写的时候,并不需要cpu为其分配时间片进行操作,所以对于操作系统而言,也就把io操作归为阻塞状态。
这时就有问题,那Java层面的io操作属于什么层面。 在Java层面的io操作属于RUNNABLE状态,因为当线程调用阻塞式 API,线程进入休眠状态,这里指的是操作系统层面的。从 JVM 层面,Java 线程状态依然处于 RUNNABLE 状态。JVM 并不关心操作系统线程实际状态。从 JVM 看来等待 CPU 使用权(操作系统线程状态为可运行状态)与等待 I/O (操作系统线程状态处于休眠状态)没有区别,都是在等待某种资源,所以都归入 RUNNABLE 状态。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情
