三、线程状态
3.1 线程停止
1.建议线程正常停止----->利用次数,不建议死循环
2.不要使用stop或者destroy等过时或者JDK不建议使用的方法
3.建议使用标志位----->设置标志位 (自己写stop方法)
public class TestStop 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 stop(){
this.flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);//当输出到main900的时候,线程testStop结束,run...Thread不在输出,只输出main901-main999
if (i == 900){
//调用stop方法切换标记位,让线程停止
testStop.stop();
System.out.println("该线程停止了");
}
}
}
}
运行结果:
main0
run.......Thread0
main1
run.......Thread1
main2
run.......Thread2
main和run...Thread交替出现
~~~~~~~
main887
main888
run.......Thread906
main889
main890
main891
main892
main893
main894
main895
main896
main897
main898
main899
main900
run.......Thread907
run.......Thread908
该线程停止了
main901
main902
main903
main904
.........
main990
main991
main992
main993
main994
main995
main996
main997
main998
main999
3.2 线程休眠-sleep
案例1:
//模拟网络延迟:方法问题的发生性
//如果不模拟延迟,线程不安全(后续学习会解决)火车票可能会被会被同一个人抢完
public class TestSleep implements Runnable{
private 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张火车票
李华---->拿了第10张火车票
小明---->拿了第9张火车票
小明---->拿了第8张火车票
黄牛---->拿了第8张火车票
李华---->拿了第7张火车票
李华---->拿了第6张火车票
小明---->拿了第6张火车票
黄牛---->拿了第6张火车票
李华---->拿了第5张火车票
黄牛---->拿了第4张火车票
小明---->拿了第5张火车票
黄牛---->拿了第1张火车票
李华---->拿了第2张火车票
小明---->拿了第3张火车票
原因------>线程不安全
案例2:
模拟倒计时,然后输出当前时间
//模拟倒计时
public class TestSleep02 {
//模拟倒计时
public static void tenDown() throws InterruptedException {
int num = 10;
while (true){
Thread.sleep(1000);
System.out.println(num--);
if (num <= 0){
break;
}
}
}
public static void main(String[] args) {
try {
tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
//模拟打印当前时间
Date startTime = new Date(System.currentTimeMillis());//获取当前系统时间
while (true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
startTime = new Date(System.currentTimeMillis());//更新当前时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果:
10
9
8
7
6
5
4
3
2
1
15:36:23
15:36:24
15:36:25
15:36:26
15:36:27
15:36:28
......
3.3 线程礼让-yield
线程礼让:让当前正在执行的线程暂停,但不阻塞
将线程从运行状态转为就绪状态
让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()+"线程停止执行");
}
}
//没有礼让--Yield
//按照顺序
a线程开始执行
a线程停止执行
b线程开始执行
b线程停止执行
//礼让,输出a线程开始执行后,还没有输出停止,就礼让输出b线程开始执行
a线程开始执行
b线程开始执行
b线程停止执行
a线程停止执行
3.4 线程强制执行-Join
线程强制执行:原来主线程和子线程是并行的关系,使用Join后,就会变为串行的关系,也就是,子线程执行Join后,子线程插入到主线程中,必须要等子线程运行完才能运行主线程。
类比:好比几个人乱着,有个线程a使用Join()插到最前面,我执行完你们再抢。
//测试join方法 //理解为插队
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 50; 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 = 0; i < 50; i++) {
if (i == 20){
thread.join();//插队
}
System.out.println("main"+i);
}
}
}
运行结果:
//因为我这台电脑的处理器是四核的,所以刚开始输出会出现主线程和子线程都出现的情况(因为几个内核执行一个线程)
//当main中i==20,子线程使用Join()让塔先执行完,再执行main线程
main0
线程vip来了0
main1
线程vip来了1
main2
线程vip来了2
main3
线程vip来了3
main4
线程vip来了4
main5
线程vip来了5
main6
线程vip来了6
main7
线程vip来了7
main8
线程vip来了8
main9
线程vip来了9
main10
线程vip来了10
main11
线程vip来了11
main12
main13
线程vip来了12
main14
线程vip来了13
main15
线程vip来了14
main16
main17
main18
main19
线程vip来了15
线程vip来了16
线程vip来了17
线程vip来了18
线程vip来了19
线程vip来了20
线程vip来了21
线程vip来了22
线程vip来了23
线程vip来了24
线程vip来了25
线程vip来了26
线程vip来了27
线程vip来了28
线程vip来了29
线程vip来了30
线程vip来了31
线程vip来了32
线程vip来了33
线程vip来了34
线程vip来了35
线程vip来了36
线程vip来了37
线程vip来了38
线程vip来了39
线程vip来了40
线程vip来了41
线程vip来了42
线程vip来了43
线程vip来了44
线程vip来了45
线程vip来了46
线程vip来了47
线程vip来了48
线程vip来了49
main20
main21
main22
main23
main24
main25
main26
main27
main28
main29
main30
main31
main32
main33
main34
main35
main36
main37
main38
main39
main40
main41
main42
main43
main44
main45
main46
main47
main48
main49
Process finished with exit code 0
3.5 线程状态观测
-
线程状态。 线程可以处于以下状态之一:
NEW
尚未启动的线程处于此状态。RUNNABLE
在Java虚拟机中执行的线程处于此状态。BLOCKED
被阻塞等待监视器锁定的线程处于此状态。WAITING
正在等待另一个线程执行特定动作的线程处于此状态。TIMED_WAITING
正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。TERMINATED
已退出的线程处于此状态。
一个线程可以在给定时间点处于一个状态。 这些状态是不反映任何操作系统线程状态的虚拟机状态。
-
-
[BLOCKED] 一个线程的线程状态阻塞等待监视器锁定。 [NEW] 线程尚未启动的线程状态。 [RUNNABLE] 可运行线程的线程状态。 [TERMINATED] 终止线程的线程状态。 [TIMED_WAITING] 具有指定等待时间的等待线程的线程状态。 [WAITING] 等待线程的线程状态
-
案例:
//观察测试线程的状态
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);//Run
while (state != Thread.State.TERMINATED){//只要线程不终止,就一直输出状态
Thread.sleep(100);
state = thread.getState();//更新状态
System.out.println(state);//输出
}
// thread.start();//出现错误,因为死亡后的线程不能再启动
}
}
NEW
RUNNABLE
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
/
TERMINATED
Process finished with exit code 0
3.6 线程优先级
- Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该先先调用那个线程来执行,优先级高的先调用的可能性高,但并不是一定是按照优先级来的。
- 线程的优先级用数字表示,范围从1~10
Thread.MAX_PRIORITY = 10
Thread.MIN_PRIORITY = 1
Thread.NORM_PRIORITY = 5
-
使用一下方式修改或获取优先级
getPriority() setPriority()
//测试线程的优先级
public class TestPrioruty extends Thread{
public static void main(String[] args) {
//输出主线程默认优先级
System.out.println(Thread.currentThread().getName()+"------>"+Thread.currentThread().getPriority());
MyPrioruty myPrioruty = new MyPrioruty();
Thread t1 = new Thread(myPrioruty);
Thread t2 = new Thread(myPrioruty);
Thread t3 = new Thread(myPrioruty);
Thread t4 = new Thread(myPrioruty);
Thread t5 = new Thread(myPrioruty);
Thread t6 = new Thread(myPrioruty);
//先设置优先级,再启动
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);
t4.start();
// t5.setPriority(-1);
// t5.start();
//
// t6.setPriority(11);
// t6.start();
}
}
class MyPrioruty implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"------>"+Thread.currentThread().getPriority());
}
}
3.7 守护(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);//默认是false表示是用户线程,正常的线程都是用户线程
thread.start();//上帝守护线程启动
new Thread(you).start();
}
}
//上帝
class God implements Runnable{
@Override
public void run() {
while (true){// 虚拟机不用等待守护线程执行完毕,所以守护线程最后死亡
System.out.println("上帝忽悠你");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("你一生都痛苦的活着");
}
System.out.println("=============goodbye,world!=====================");
}
}
运行结果:
你一生都痛苦的活着
你一生都痛苦的活着
你一生都痛苦的活着
你一生都痛苦的活着
你一生都痛苦的活着
=============goodbye,world!=====================
上帝忽悠你
上帝忽悠你
上帝忽悠你
上帝忽悠你
上帝忽悠你
上帝忽悠你
上帝忽悠你
上帝忽悠你
上帝忽悠你
上帝忽悠你
上帝忽悠你
上帝忽悠你
上帝忽悠你