[Java][华为云Java编程创造营][学习笔记][第三阶段][05_Java多线程实战][02_线程生命周期和状态]
【摘要】 2.1,线程的生命周期和状态在线程的生命周期中,它要经过新建(New),就绪(Runnable),运行(Running),阻塞(Blocked)和死亡(Dead)5种状态。当线程启动以后,它不可能一直”霸占“着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。线程的生命周期五个阶段:新建状态,当程序使用new关键字创建了一个线程之后,该线程就处于新...
2.1,线程的生命周期和状态
-
在线程的生命周期中,它要经过新建(New),就绪(Runnable),运行(Running),阻塞(Blocked)和死亡(Dead)5种状态。
-
当线程启动以后,它不可能一直”霸占“着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。
-
线程的生命周期五个阶段:
- 新建状态,当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值。
- 就绪状态,当线程对象调用了start()方法之后,该线程处于就绪状态。JVM会为其创建方法调用栈和程序计数器,等待调度运行。
- 运行状态,如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。
- 阻塞状态,当处于运行状态的线程失去所占用资源之后,便进入阻塞状态。
- 在线程的生命周期当中,线程的各种状态的转换过程。
2.2,线程的睡眠
- 线程休眠的方法是Thread.sleep(long millis)
- 线程休眠的目的是使线程让出CPU的最简单的做法之一,线程休眠的时候,会将CPU资源交给其他线程,以便能轮换执行,当休眠一定时间后,线程会苏醒,进入准备状态等待执行。
- 简单说,哪个线程调用sleep方法,就休眠哪个线程。
class UserThread extends Thread
{
public void run()
{
System.out.println(Thread.currentThread().getName() + ",A");
try
{
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ",B");
}
}
public class Demo19
{
public static void main(String[] args)
{
/*
* 线程的执行顺序不能精确控制,哪个线程执行sleep方法,就休眠,一定让出执行权给其他线程
* */
UserThread u1 = new UserThread();
UserThread u2 = new UserThread();
u1.start();
u2.start();
/*
* 输出结果
* Thread-0,A
Thread-1,A
Thread-0,B
Thread-1,B
* */
}
}
2.3,线程的让步
- yield()的作用是让步。它能让当前线程由"运行状态"进入"就绪状态",从而让其他具有相同优先级的等待线程获取执行权。
- 但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;也有可能是当前线程又进入到"运行状态"继续运行。
- 简单地说,就是哪个线程执行yield方法,就是礼让。
class UserThread extends Thread
{
public void run()
{
System.out.println(Thread.currentThread().getName() + ",A");
Thread.yield();
System.out.println(Thread.currentThread().getName() + ",B");
}
}
public class Demo20
{
public static void main(String[] args)
{
/*
* 线程yield让步,执行权可能让给其它线程,也可能让给自己,让步可以理解成礼让
* */
UserThread u1 = new UserThread();
UserThread u2 = new UserThread();
u1.start();
u2.start();
/*
* 输出结果
* Thread-0,A
Thread-0,B
Thread-1,A
Thread-1,B
* */
}
}
2.4,线程的合并
- 线程的合并的作用就是将几个并行线程合并为一个单线程执行。
- 当一个线程必须等待另一个线程执行完毕才能执行时可以使用join方法。
class UserThread extends Thread
{
public void run()
{
for (int i = 0; i < 10; i++)
{
System.out.println("线程1第" + i + "次执行!");
}
}
}
public class Demo21
{
public static void main(String[] args)
{
UserThread ut = new UserThread();
ut.start();
for (int i = 0; i < 20; i++)
{
System.out.println("主线程第" + i + "次执行");
try
{
ut.join();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
/*
* 输出结果
* 主线程第0次执行
线程1第0次执行!
线程1第1次执行!
线程1第2次执行!
线程1第3次执行!
线程1第4次执行!
线程1第5次执行!
线程1第6次执行!
线程1第7次执行!
线程1第8次执行!
线程1第9次执行!
主线程第1次执行
主线程第2次执行
主线程第3次执行
主线程第4次执行
主线程第5次执行
主线程第6次执行
主线程第7次执行
主线程第8次执行
主线程第9次执行
主线程第10次执行
主线程第11次执行
主线程第12次执行
主线程第13次执行
主线程第14次执行
主线程第15次执行
主线程第16次执行
主线程第17次执行
主线程第18次执行
主线程第19次执行
* */
}
}
2.5,守护线程
- 调用线程对象的方法setDaemon(true),则可以将其设置为守护线程。
- JVM的垃圾回收、内存管理等线程都是守护线程。
- setDaemon(boolean on):将该线程标记为守护线程或用户线程。
- 当正在运行的线程都是守护线程时,JVM退出。
- 该方法必须在启动线程前调用。
2.6,线程的中断和死亡
- 线程中断就是让目标线程停止执行,但它不会使线程立即终止,而是给线程发送一个通知,告诉线程JVM希望退出执行,至于目标线程何时退出,则完全由它自己决定。
public class Demo22
{
public static void main(String[] args)
{
Thread thread = new Thread()
{
@Override
public void run()
{
while (true)
{
//判断当前线程是否是中断状态
if (this.isInterrupted())
{
System.out.println("===true===");
break;
}
}
}
};
thread.start();
try
{
Thread.sleep(3000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
//调用线程中断方法
thread.interrupt();
/*
* 输出结果
* ===true===
* */
}
}
-
线程会以如下三种方式结束,结束后就处于死亡状态。
- run()或call()方法执行完成,线程正常结束。
- 线程抛出一个未捕获的Exception或Error。
- 直接调用该线程的stop方法结束该线程–该方法容易导致死锁,建议不使用。
-
注意:不要对一个死亡的线程调用start方法使它重新启动,死亡就是死亡,该线程不可能再次作为线程执行。
public class Demo23
{
//退出标志
public static boolean exit = false;
public static void main(String[] args)
{
new Thread()
{
@Override
public void run()
{
System.out.println("线程启动了");
while (!exit)
{
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println("线程结束了");
}
}.start();
try
{
Thread.sleep(1000 * 5);
} catch (InterruptedException e)
{
e.printStackTrace();
}
//5秒后更改退出标志的值,没有这段代码,线程就一直不能停止
exit = true;
/*
* 输出结果
* 线程启动了
线程结束了
* */
}
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)