线程状态
▪ 新生状态(New)
用new关键字建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态。
▪ 就绪状态(Runnable)
处于就绪状态的线程已经具备了运行条件,但是还没有被分配到CPU,处于“线程就绪队列”,等待系统为其分配CPU。就绪状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会进入执行状态。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。有4中原因会导致线程进入就绪状态:
1. 新建线程:调用start()方法,进入就绪状态;
2. 阻塞线程:阻塞解除,进入就绪状态;
3. 运行线程:调用yield()方法,直接进入就绪状态;
4. 运行线程:JVM将CPU资源从本线程切换到其他线程。
▪ 运行状态(Running)
在运行状态的线程执行自己run方法中的代码,直到调用其他方法而终止或等待某资源而阻塞或完成任务而死亡。如果在给定的时间片内没有执行结束,就会被系统给换下来回到就绪状态。也可能由于某些“导致阻塞的事件”而进入阻塞状态。
▪ 阻塞状态(Blocked)
阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪)。有4种原因会导致阻塞:
1. 执行sleep(int millsecond)方法,使当前线程休眠,进入阻塞状态。当指定的时间到了后,线程进入就绪状态。
2. 执行wait()方法,使当前线程进入阻塞状态。当使用nofity()方法唤醒这个线程后,它进入就绪状态。
3. 线程运行时,某个操作进入阻塞状态,比如执行IO流操作(read()/write()方法本身就是阻塞的方法)。只有当引起该操作阻塞的原因消失后,线程进入就绪状态。
4. join()线程联合: 当某个线程等待另一个线程执行结束后,才能继续执行时,使用join()方法。
▪ 死亡状态(Terminated)
死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有两个。一个是正常运行的线程完成了它run()方法内的全部工作; 另一个是线程被强制终止,如通过执行stop()或destroy()方法来终止一个线程(注:stop()/destroy()方法已经被JDK废弃,不推荐使用)。
当一个线程进入死亡状态以后,就不能再回到其它状态了。
线程控制方法
一、join()加入线程
调用join()方法后,主线程会进入阻塞,直到调用join()的线程执行完成,才继续回到主线程。
join()方法使用思路:join()方法主要由使用线程的程序使用,将大问题分解为许多个小问题,每个小问题分配一个线程,当所有小问题都解决完后,再回到主线程进行进一步操作。
public class JoinDemo01 extends Thread {
public static void main(String[] args) throws InterruptedException {
JoinDemo01 demo = new JoinDemo01();
Thread t = new Thread(demo);
t.start();
for(int i=0;i<1000;i++){
if(50==i){
t.join(); //main方法阻塞,直到t对应线程结束
}
System.out.println("main...."+i);
}
}
@Override
public void run() {
for(int i=0;i<1000;i++){
System.out.println("join...."+i);
}
}
}
二、后台线程/守护线程/精灵线程
将线程设置为后台线程:t.setDaemon(true);
启动线程:t.start();
要设置线程为后台线程必须在启动线程之前。
可使用isDaemon判断线程是否后台线程
如果所有的前台线程都死亡,后台线程也会自动死亡。
主线程默认是前台线程,前台线程的子线程默认是前台线程,后台线程的子线程默认是后台线程。
三、线程睡眠sleep()
• 使线程停止运行一段时间,将处于阻塞状态
• 如果调用了sleep方法之后,没有其他等待执行的线程,这个时候当前线程不会马上恢复执行!
class testThread{
public static void main(String args[]) throws Exception{
Thread.sleep(1000);
Thread.currentThread().sleep(10000);
}
}
四、线程让步yield()
• 让当前正在执行线程暂停,不是阻塞线程,而是将线程转入就绪状态
• 如果调用了yield方法之后,没有其他等待执行的线程,这个时候当前线程就会马上恢复执行!
Thread.yield(); //让当前线程让步