线程的状态
新生状态:用new关键字和Thread类或子类建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(Runnable)
就绪状态:处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列,等待系统为其分配CPU。等待状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态,系统挑选的动作称之为“CPU调度”。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法
运行状态:在运行状态的线程执行自己的run方法中代码,直到调用其它方法而终止、或等待某资源而阻塞或完成任务而死亡。如果在给定的时间片内没有执行结束,就会被系统给换下来回到等待执行状态。
阻塞状态:处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己的运行,进入阻塞状态。在阻塞状态的线程不能进入就绪状态,只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续运行 。
死亡状态:死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有两个。一个是正常运行的线程完成了它的全部工作;另一个是线程被强制性地终止,如通过执行stop或destroy方法来终止一个线程(不推荐使用这两个方法。前者会产生异常,后者是强制终止,不会释放锁。)
停止线程
/**
* 停止线程
1、自然终止:线程体正常执行完毕
2、外部干涉:
——线程类中定义线程体使用的标识
——线程体使用该标识
——提供对外的方法改变该标识
——外部根据条件调用该方法即可
* @author Administrator
*
*/
public class TestDeath {
public static void main(String[] args) {
read r = new read();
Thread t = new Thread(r);
t.start();
for(int i=0;i<50;i++){
//外部干涉
if(i==25){
r.stop(); //当i=25之后,后面read线程不在执行!!
System.out.println("学习了"+i+"次");
}
System.out.println("执行第"+i+"个main方法中");
}
}
}
class read implements Runnable{
//线程类中定义线程体使用的标识
private boolean flag=true;
private int i = 0; //计数
@Override
public void run() {
//线程体使用该标识
while(flag){
System.out.println("正在学习中!"+(i++));
}
}
//对外提供方法改变标识
public void stop(){
this.flag = false;
}
}
线程阻塞
处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己的运行,进入阻塞状态。在阻塞状态的线程不能进入就绪状态,只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续运行 。所以线程阻塞主要讲三个方法:
1、join:合并线程
2、yield:暂停自己的线程(static方法,暂停一下,可能下一毫秒又被调用,这由CPU决定)
3、sleep:休眠,不释放锁
——1)与时间相关:倒计时
——2)模拟网络延时
/**
* join:合并线程
*/
public class TestJoin extends Thread {
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin = new TestJoin();
Thread t = new Thread(testJoin);//新生状态
t.start();//就绪状态
//CPU调度 运行
for (int i = 0; i < 30; i++) {
if(10==i){
t.join();//main阻塞,等待t执行完
}
System.out.println("main..."+i);
}
}
@Override
public void run() {
for (int i = 0; i < 30; i++) {
System.out.println("join..."+i);
}
}
}
/**
* yield:暂停自己的线程(static方法,暂停一下,可能下一毫秒又被调用,这由CPU决定)
*/
public class TestYield extends Thread {
public static void main(String[] args) {
TestYield testYield = new TestYield();
Thread t = new Thread(testYield);
t.start();
for (int i = 0; i < 100; i++) {
if(0==i%20){
//暂停当前线程,写在哪个线程体里面就暂停哪个线程
Thread.yield();//暂停一下,可能下一毫秒又被调用,这由CPU决定
}
System.out.println("main..."+i);
}
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("yield..."+i);
}
}
}
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestSleep {
public static void main(String[] args) {
try {
// test01();
test02();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//倒数十个数
public static void test01() throws InterruptedException{
int num = 10;
while(num>=0){
Thread.sleep(1000);
System.out.println(num--);
}
}
//倒计时
public static void test02() throws InterruptedException{
Date endtime = new Date(System.currentTimeMillis()+10*1000);
long end = endtime.getTime();
while(true){
//输出
System.out.println(new SimpleDateFormat("mm:ss").format(endtime));
//等待一秒
Thread.sleep(1000);
//构建下一秒时间
endtime = new Date(endtime.getTime() - 1000);
//10秒以内继续,否则退出
if(end-10000 > endtime.getTime()){
break;
}
}
}
}