线程的状态/生命周期
Java中线程的状态分为6种:
1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
3. 阻塞(BLOCKED):表示线程阻塞于锁(在当前java中只有synchornized能够让其阻塞)。
4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
5. 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
6. 终止(TERMINATED):表示该线程已经执行完毕。
状态之间的变迁如下图所示
掌握这些状态可以让我们在进行Java程序调优时可以提供很大的帮助。
其他的线程相关方法
yield()方法:使当前线程让出CPU占有权,但让出的时间是不可设定的。也不会释放锁资源。同时执行yield()的线程有可能在进入到就绪状态后会被操作系统再次选中马上又被执行。
比如,ConcurrentHashMap#initTable 方法中就使用了这个方法,
这是因为ConcurrentHashMap中可能被多个线程同时初始化table,但是其实这个时候只允许一个线程进行初始化操作,其他的线程就需要被阻塞或等待,但是初始化操作其实很快,这里Doug Lea大师为了避免阻塞或者等待这些操作引发的上下文切换等等开销,就让其他不执行初始化操作的线程干脆执行yield()方法,以让出CPU执行权,让执行初始化操作的线程可以更快的执行完成。
wait()/notify()/notifyAll():后面会单独讲述
线程的优先级
在Java线程中,通过一个整型成员变量priority来控制优先级,优先级的范围从1~10,在线程构建的时候可以通过setPriority(int)方法来修改优先级,默认优先级是5,优先级高的线程分配时间片的数量要多于优先级低的线程。
设置线程优先级时,针对频繁阻塞(休眠或者I/O操作)的线程需要设置较高优先级,而偏重计算(需要较多CPU时间或者偏运算)的线程则设置较低的优先级,确保处理器不会被独占。在不同的JVM以及操作系统上,线程规划会存在差异,有些操作系统甚至会忽略对线程优先级的设定。
线程的调度
线程调度是指系统为线程分配CPU使用权的过程,主要调度方式有两种:
协同式线程调度(Cooperative Threads-Scheduling)
抢占式线程调度(Preemptive Threads-Scheduling)
使用协同式线程调度的多线程系统,线程执行的时间由线程本身来控制,线程把自己的工作执行完之后,要主动通知系统切换到另外一个线程上。