线程状态分类
Java有6中状态:
序号
状态
含义
1
初始(NEW)
新创建了一个线程对象,但还没有调用start()方法。
2
运行(RUNNABLE),也可以分成拆解成了Ready就绪状态与Running运行状态
Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
3
阻塞(BLOCKED)
表示线程阻塞于锁。
4
等待(WAITING)
进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
5
超时等待(TIMED_WAITING)
该状态不同于WAITING,它可以在指定的时间后自行返回。
6
终止(TERMINATED)
该线程已经执行完毕。
线程状态切换图
图一
图二
初始状态(NEW)
实现Runnable接口和继承Thread声明一个线程类,new一个实例出来,线程就进入了初始状态。
就绪状态(RUNNABLE之READY)
就绪状态只是说你资格运行,调度程序(Cpu)没有挑选到你,你就永远是就绪状态。
调用线程的start()方法,此线程进入就绪状态。
当前线程sleep()方法结束,其他线程join()结束,等待用户输入完毕,某个线程拿到对象锁,这些线程也将进入就绪状态。
当前线程时间片用完了,调用当前线程的yield()方法,当前线程进入就绪状态。
锁池里的线程拿到对象锁后,进入就绪状态。
运行中状态(RUNNABLE之RUNNING)
线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一的一种方式。换句话说,线程获取到了CPU时间片。
当线程时间片用完或调用的yield()函数,该线程回到就绪状态。
阻塞状态(BLOCKED)
阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态。
等待(WAITING)
处于这种状态的线程不会被分配CPU执行时间,它们要等待被显式地唤醒,否则会处于无限期等待的状态。
运行状态的线程执行wait()、join()、LockSupport.park()任意函数,该线程进入等待状态。
其中wait()与join()函数会让JVM把该线程放入锁等待队列。
处于这种状态的线程不会被分配CPU执行时间,它们要等待被主动唤醒,否则会一直处于等待状态。
如果我们要唤醒线程怎么办呢?
执行LockSupport.unpark(t)函数唤醒指定线程,该线程回到就绪状态。
而通过notify()、notifyAll()、join线程执行完毕方式,会唤醒锁等待队列的线程,出队的线程回到就绪状态。
超时等待(TIMED_WAITING)
处于这种状态的线程不会被分配CPU执行时间,不过无须无限期等待被其他线程显示地唤醒,在达到一定时间后它们会自动唤醒。
以下函数会触发进入超时等待状态
join(long)
LockSupport.parkNanos(long)
LockSupport.parkUtil(long)
sleep(long)
其中wait(long)、join(long)函数会让J V M把线程放入锁等待队列。
后面的唤醒剧情就和等待状态如出一辙,就多了超时时间到了,自动唤醒的动作。
终止状态(TERMINATED)
当线程的run()方法完成时,或者主线程的main()方法完成时,我们就认为它终止了。这个线程对象也许是活的,但是它已经不是一个单独执行的线程。线程一旦终止了,就不能复生。
在一个终止的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。
等待队列
同步队列状态
当前线程想调用对象A的同步方法时,发现对象A的锁被别的线程占有,此时当前线程进入同步队列。
简言之,同步队列里面放的都是想争夺对象锁的线程。
当一个线程1被另外一个线程2唤醒时,1线程进入同步队列,去争夺对象锁。
同步队列是在同步的环境下才有的概念,一个对象对应一个同步队列。
线程等待时间到了或被notify/notifyAll唤醒后,会进入同步队列竞争锁,如果获得锁,进入RUNNABLE状态,否则进入BLOCKED状态等待获取锁。
线程类或对象的方法
Thread.sleep(long millis)
一定是当前线程调用此方法,当前线程进入TIMED_WAITING状态,但不释放对象锁,millis后线程自动苏醒进入就绪状态。作用:给其它线程执行机会的最佳方式。
Thread.yield()
一定是当前线程调用此方法,当前线程放弃获取的CPU时间片,但不释放锁资源,由运行状态变为就绪状态,让OS再次选择线程。
作用:让相同优先级的线程轮流执行,但并不保证一定会轮流执行。实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。Thread.yield()不会导致阻塞。该方法与sleep()类似,只是不能由用户指定暂停多长时间。
sleep()方法和yield()方法的区别
sleep()方法给其他线程运行机会时不考虑线程的优先级, 因此会给低优先级的线程以运行的机会, 而yield() 方法只会给相同优先级或更高优先级的线程以运行的机会。
线程执行sleep()方法后会转入阻塞状态, 所以执行sleep()方法的线程在指定的时间内肯定不会被执行,而 yield方法只是使当前线程重新回到可执行状态, 所以执行yield()方法的线程有可能在进入到可执行状态后马上又被执行。
thread.join()/thread.join(long millis)
线程插队,例如: 线程A,执行了线程B的join方法,线程A必须要等待B执行完成了以后, 线程A才能继续自己的工作。
当前线程里调用其它线程t的join方法,当前线程进入WAITING/TIMED_WAITING状态,当前线程不会释放已经持有的对象锁。线程t执行完毕或者millis时间到,当前线程一般情况下进入RUNNABLE状态,也有可能进入BLOCKED状态(因为join是基于wait实现的)。
obj.wait()
当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列。依靠notify()/notifyAll()唤醒或者wait(long timeout) timeout时间到自动唤醒。
obj.notify()
唤醒在此对象监视器上等待的单个线程,选择是任意性的。notifyAll()唤醒在此对象监视器上等待的所有线程。
LockSupport.park()/LockSupport.parkNanos(long nanos),LockSupport.parkUntil(long deadlines)
当前线程进入WAITING/TIMED_WAITING状态。对比wait方法,不需要获得锁就可以让线程进入WAITING/TIMED_WAITING状态,需要通过LockSupport.unpark(Thread thread)唤醒。
getId()
线程的ID是唯一标识
getName
线程的名称,如果不设置线程名称默认为“Thread-xx”。
getPriority
线程的优先级,线程优先级从1-10,其中数字越大表示优先级别越高,同时获得JVM调度执行的可能性越大。
创建线程
继承Thread类,并覆盖run方法,通过start调用Thread子类对象
class Demo extends Thread{
Demo(String name)
{
//父类构造函数,改线程的名称
super(name);
}
//***run方法中定义就是线程要运行的任务代码。***
public void run()
{
for(int x = 0; x < 10; x++)
{
System.out.println(x + " name="+Thread.currentThread().getName());
}
}
}
class Thread1
{
public static void main(String[] args)
{
Demo d1 = new Demo("Demo1");
Demo d2 = new Demo("Demo2");
//开启线程,调用run方法。
d1.start();
d2.start();
System.out.println("over...."+Thread.currentThread().getName());
}
}
实现Runnable接口
class Demo2 implements Runnable{public void run()
{
for(int x=0; x<20; x++)
{
System.out.println(Thread.currentThread().getName() + " " + x);
}
}
}
class Thread2
{
public static void main(String[] args)
{
Demo2 d = new Demo2();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t2.start();
}
}
实现Callable接口
相比Runable,Callable实现类call可以有返回值,可以抛出异常,支持泛型。
import java.util.ArrayList;import java.util.concurrent.*;
class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id) {
this.id = id;
}
@Override
public String call() throws Exception {
return "result of TaskWithResult " + id;
}
}
public class Thread3 {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
ExecutorService exec = Executors.newCachedThreadPool();
//Future 相当于是用来存放Executor执行的结果的一种容器
ArrayList<Future<String>> results = new ArrayList<Future<String>>();
for (int i = 0; i < 10; i++) {
results.add(((ExecutorService) exec).submit(new TaskWithResult(i)));
}
for (Future<String> fs : results) {
if (fs.isDone()) {
System.out.println(fs.get());
} else {
System.out.println("Future result is not yet complete");
}
}
exec.shutdown();
}
}