文章目录
5.线程状态
1)五大线程状态
2)线程方法
方法 | 说明 |
---|---|
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止【类似插队】 |
static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt() | 中断线程,别用这个方式 |
boolean isAlive() | 测试线程是否处于活动状态 |
3)死亡状态-停止线程
- 不推荐使用
JDK
提供的stop()、destory()方法。
【已废弃】 - 推荐线程自己停止下来
建议使用一个标志位进行终止变量:当flag=false,则终止线程运行
。
代码实现
// 线程状态-死亡状态-停止线程
/**
测试stop
1.建议线程正常停止--->利用次数,不建议死循环
2.建议使用标志位---> 设置一个标志位
3.不要使用stop或者destroy等过时或者JDK不建议使用的方法
*/
/**
* 步骤:
* 1.实现Runnable()接口
* 2.重写run()方法
* 3.开启线程:new Thread(xxxxx).start();
*/
public class ThreadStop implements Runnable {
// 1.设置一个标志位
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag) {
System.out.println("run------>Thread:" + (i++));
}
}
// 2.设置一个公开的方法停止线程,转换标志位
public void threadStopMethod(){
this.flag = false;
}
public static void main(String[] args) {
// 创建线程
ThreadStop threadStop = new ThreadStop();
// 开启线程
new Thread(threadStop).start();
for (int i = 0; i < 100; i++) {
System.out.println("main线程>>>>>>>"+i);
if (i == 5) {
//调用stop方法停止并且切换标志位
threadStop.threadStopMethod();
System.out.println("线程被停止!!!"+i);
}
}
}
}
执行结果[注意:每次执行的结果都是不相同的!]
main线程>>>>>>>0
main线程>>>>>>>1
run------>Thread:0
run------>Thread:1
......
run------>Thread:35
main线程>>>>>>>2
main线程>>>>>>>3
main线程>>>>>>>4
main线程>>>>>>>5
run------>Thread:36
线程被停止!!!5
main线程>>>>>>>6
main线程>>>>>>>7
......
main线程>>>>>>>99
4)阻塞状态-线程休眠
- sleep(时间)指定当前线程阻塞的毫秒数;
- sleep 存在异常
InterruptedException
; - sleep 时间达到后线程进入就绪状态;
- sleep 可以模拟网络延时,倒计时等;
每一个对象都有一个锁,sleep 不会释放锁;
模拟网络延时-代码实现:
/**
* 模拟网络延时:
* 问题:
* 线程不安全。
* 作用:
* 放大问题的发生性。
*/
public class TestSleep implements Runnable{
// 票数量
int ticketNums = 10;
@Override
public void run() {
while (true) {
if (ticketNums <= 0) {
break;
}
// 模拟延时
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ">>>拿到了第"+ (ticketNums--) +"票");
}
}
public static void main(String[] args) {
// 一份资源
TestSleep ticket = new TestSleep();
// 多份线程
new Thread(ticket,"张三").start();//给线程起名字
new Thread(ticket,"李四").start();
new Thread(ticket,"王五").start();
}
}
执行结果:
李四>>>拿到了第10票
张三>>>拿到了第8票
王五>>>拿到了第9票
张三>>>拿到了第7票
王五>>>拿到了第6票
李四>>>拿到了第5票
李四>>>拿到了第3票
王五>>>拿到了第4票
张三>>>拿到了第2票
张三>>>拿到了第1票
王五>>>拿到了第0票
李四>>>拿到了第-1票
----------------------
出现线程不安全的情况!
模拟倒计时-代码实现
// 模拟倒计时
public class TestSleep2 {
/*public static void main(String[] args) {
try {
tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}*/
public static void main(String[] args) {
// 打印系统当前时间
Date date = new Date(System.currentTimeMillis());
while (true) {
try {
// 间隔一秒
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
//更新时间
date = new Date(System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 倒计时方法
public static void tenDown() throws InterruptedException {
int num = 10;
while (true) {
// 每间隔一秒打印一个值
Thread.sleep(1000);
System.out.println(num--);
if (num <= 0) {
break;
}
}
}
}
5)就绪状态-线程礼让
- 礼让线程,让当前正在执行的线程暂停,但不阻塞
- 将线程从运行状态转为就绪状态
- 让
cpu
重新调度,礼让不一定成功!看cpu
心情
图形讲解-线程礼让
代码实现:
// 测试礼让线程
// 礼让不一定成功,看cpu心情
public class TestYield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行");
Thread.yield();//礼让
System.out.println(Thread.currentThread().getName()+"线程结束执行");
}
}
执行结果1-礼让
a线程开始执行
b线程开始执行
a线程结束执行
b线程结束执行
执行结果2-没礼让
a线程开始执行
a线程结束执行
b线程开始执行
b线程结束执行
6)就绪状态-Join【其他线程变阻塞状态】
- Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
- 可以想象成插队
代码实现
// 测试join
// 可想象成插队
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 200; i++) {
System.out.println("线程vip进入"+i);
}
}
public static void main(String[] args) throws InterruptedException {
//启动线程
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
//主线程
for (int i = 1; i <= 100; i++) {
if (i == 5) {
thread.join();// 线程插队
}
System.out.println("main线程执行"+i);
}
}
}
执行结果
main线程执行1
main线程执行2
main线程执行3
main线程执行4
线程vip进入1
线程vip进入2
......
线程vip进入199
线程vip进入200
main线程执行5
main线程执行6
......
main线程执行100
7)线程状态观测-state
—在线程中观测线程的状态
-
Thread.State
线程状态:线程可以处于以下状态之一:【可查看JDK帮助文档】
- NEW 尚未启动的线程处于此状态 - RUNNABLE 在Java虚拟机中执行的线程处于此状态 - BLOCKED 被阻塞等待监视器锁定的线程处于此状态 - WATTING 正在等待另一个线程执行特定动作的线程处于此状态 - TIMED WATTING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态 - TERMINATED 已退出的线程处于此状态
一个线程可以在给定时间点处于一个状态。这些状态是不反应任何操作系统线程状态的虚拟机状态。
代码实现
// 观测线程状态
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("************************");
});
//观察线程状态
Thread.State state = thread.getState();
System.out.println(">>>>>>线程的状态为:"+state);// NEW
//观察线程启动后的状态
thread.start();//启动线程
state = thread.getState();
System.out.println(">>>>>>线程启动后的状态为:"+state);// RUNNABLE
// 此时线程运动的状态可能时跑的,也可能时死的,需要监听来查看
// 如何判断线程已经死了呢?state == Thread.State.TERMINATED 表示为线程终止/死亡
while (state != Thread.State.TERMINATED) {// 只要线程不终止,就一直输出状态
Thread.sleep(100);//避免程序过快,加个间隔
// 注意!!!!:一定要更新线程的状态,再输出
state = thread.getState();//更新线程状态
System.out.println(">>>>>>监听此时的状态:"+state);
}
// 再次注意:线程状态停止后,不能在启动线程,也就是说线程只能启动一次! thread.start();//报错!
}
}
执行结果
>>>>>>线程的状态为:NEW
>>>>>>线程启动后的状态为:RUNNABLE
>>>>>>监听此时的状态:TIMED_WAITING
......
>>>>>>监听此时的状态:TIMED_WAITING
>>>>>>监听此时的状态:RUNNABLE
>>>>>>监听此时的状态:TIMED_WAITING
......
>>>>>>监听此时的状态:TIMED_WAITING
>>>>>>监听此时的状态:RUNNABLE
************************
>>>>>>监听此时的状态:TERMINATED
8)线程优先级-priority
Java
提供一个线程调度器,来监控程序中,启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。- 线程的优先级用数字表示,范围从1~10
Thread.MIN_PRIORITY = 1;
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5;
- 使用以下方式改变或获取优先级
getPriority()
setProirity(int xxx)
代码实现:
// 测试优先级
public class TestPriority {
public static void main(String[] args) {
// 主线程默认的优先级
System.out.println(Thread.currentThread().getName() + "--->" + Thread.currentThread().getPriority());
MyPriority myPriority = new MyPriority();
Thread t1 = new Thread(myPriority);
Thread t2 = new Thread(myPriority);
Thread t3 = new Thread(myPriority);
Thread t4 = new Thread(myPriority);
Thread t5 = new Thread(myPriority);
//注意:一定是先设置线程的优先级,再启动
t1.start();
t2.setPriority(4);
t2.start();
t3.setPriority(Thread.MAX_PRIORITY);// 线程优先级最大值
t3.start();
// t4.setPriority(-1);// 小于最小线程优先级:肯定会报错
// t4.start();
// t4.setPriority(11);// 大于最大线程优先级:肯定也会报错
// t4.start();
t4.setPriority(8);
t4.start();
t5.setPriority(Thread.MIN_PRIORITY);
t5.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "--->" + Thread.currentThread().getPriority());
}
}
执行结果:不唯一
main--->5
Thread-1--->4
Thread-2--->10
Thread-0--->5
Thread-3--->8
Thread-4--->1
总结
1.优先级低只是意味着获得调度的概率低,并不是优先级低,就不会被调用了,这都是看CPU的调度。
2.优先级的设定建议在start()调度之前。
3.在实际开发中,想让某一线程有限执行,可设置线程的权重,则优先执行的概率会大大增加。
9)守护(daemon)线程
- 线程分为
用户线程
和守护线程
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 如:后台记录操作日志,监控内存,垃圾回收等待…
代码实现:
// 测试守护(daemon)线程
// 模拟:上帝守护着你
public class TestDaemon {
public static void main(String[] args) {
God god = new God();
You you = new You();
Thread thread = new Thread(god);
thread.setDaemon(true);// 将God线程设置为守护线程
thread.start();
new Thread(you).start();
}
}
// 上帝God
class God implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("上帝守护着你");
}
}
}
// 你You
class You implements Runnable {
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你每天平安开心的活着");
}
System.out.println("------------goodbye world!");
}
}