线程状态
创建状态:new一个线程
就绪状态:开始start方法
运行状态:CPU调度完成
阻塞状态:CPU调度之后未执行完
死亡状态:线程执行完之后
-线程方法
方法 | 说明 |
---|---|
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止 |
static void yield() | 暂停当前正在执行的对象,并执行其他线程 |
void interrupt() | 中断线程,不要用这个方式 |
boolean isAlive() | 测试线程是否处于活动状态 |
-线程停止
不推荐使用JDK提供的stop()、destroy()方法来停止线程
推荐让线程自己停下来
建议使用一个标志位进行终止变量,当flag = false,则终止线程
//测试stop
/*
1.建议线程正常停止 ---> 定义利用次数,不建议死循环
2.建议使用标志位 ---> 设置一个标志位,向外部提供修改标志的方法
3.不要使用stop或者destroy等过时或JDK不建议使用的方法
*/
public class TestStop implements Runnable{
//设置一个标志位
private boolean flag = true;
@Override
public void run() {
int i = 0;
while(flag){
System.out.println("run... Thead " + 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);
if(i == 900){
//3.调用stop方法改变标志位,来停止线程
testStop.stop();
System.out.println("线程该停止了");
}
}
}
}
-线程休眠 sleep
sleep(毫秒)指定当前的线程阻塞的毫秒数
sleep存在异常InterruptedException;
sleep时间达到后线程就进入就绪状态
sleep可以模拟网络延时,倒计时等
每一个对象都有一个锁,sleep不会释放锁
实例1
//模拟网络延时放大问题的发生性
//模拟抢票
public class TestSleep implements Runnable{
private int ticket = 50;
@Override
public void run() {
while(true){ //模拟人们一直抢票的动作
//模拟延时,减慢人们的抢票速度
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(ticket <= 0) { //票被抢完就退出程序
System.out.println("ticket has none!");
break;
}
System.out.println(Thread.currentThread().getName() + " 抢到了第 " + ticket-- + "张票");
}
}
public static void main(String[] args) {
//创建一个线程的实现对象
TestSleep testSleep = new TestSleep();
//多线程共享一个对象
new Thread(testSleep,"小明").start();
new Thread(testSleep,"张三").start();
new Thread(testSleep,"小李").start();
new Thread(testSleep,"王五").start();
//可能会出现抢到同一张票的情况,线程是不安全的
}
}
实例2
//模拟倒计时,打印系统时间
public class TestSleep2 {
public static void main(String[] args) {
TestSleep2 t2 = new TestSleep2();
// try { //倒计时方法
// t2.timeDown(20);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
Date startTime; //获取当前系统时间
while(true){
startTime = new Date(System.currentTimeMillis()); //获取当前系统时间
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void timeDown(int time) throws InterruptedException {
while (true){
Thread.sleep(1000);
System.out.println(time--);
if (time <= 0) break;
}
}
}
-线程礼让 yield
礼让线程,让当前正在运行的线程暂停,但是不阻塞
将线程从运行状态转换为就绪状态
yield方法会让CPU重新调度,但是礼让是不一定成功的
//测试礼让线程
//礼让不一定成功,要看CPU具体的调度
public class TestYield{
public static void main(String[] args) {
new Thread(() -> { //Lambda表达式,简写Runnable函数式接口
System.out.println(Thread.currentThread().getName() + " Thread Start");
//Thread.yield(); //调用线程的礼让
System.out.println(Thread.currentThread().getName() + " Thread Stop");
},"A").start();
new Thread(() -> { //Lambda表达式,简写Runnable函数式接口
System.out.println(Thread.currentThread().getName() + " Thread Start");
//Thread.yield(); //调用线程的礼让
System.out.println(Thread.currentThread().getName() + " Thread Stop");
},"B").start();
MyYield myYield = new MyYield();
new Thread(myYield,"一").start();
new Thread(myYield,"二").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 线程开始");
Thread.yield();
System.out.println(Thread.currentThread().getName() + " 线程结束");
}
}
/*某一次输出结果
A Thread Start
二 线程开始
一 线程开始
A Thread Stop
B Thread Start
二 线程结束
B Thread Stop
一 线程结束
*/
-线程强制执行 join
Join合并线程,等待此线程执行完成后,再执行其它线程
可以想象为插队
//测试join方法,想象为插队
public class TestJoin {
public static void main(String[] args) throws InterruptedException {
//启动定义的线程
// VIP vip = new VIP();
// Thread thread = new Thread(vip);
// thread.start();
//简化写法
Thread thread = new Thread(()->{
for (int i = 0; i <= 20; i++) {
new MySleep().Asleep(300); //模拟插队线程执行很慢造成阻塞
System.out.println("VIP run..." + i);
}
});
thread.start();
//主线程
for (int i = 0; i <= 10; i++) {
if(i == 5) thread.join(); //主程序执行一半,让VIP线程插队
System.out.println("main run... " + i);
}
}
}
//class VIP implements Runnable{
// @Override
// public void run() {
// for (int i = 0; i <= 20; i++) {
// new MySleep().Asleep(100);
// System.out.println("VIP run..." + i);
// }
// }
//}
-线程的状态观测 Thread.state
线程状态,线程可以处于以下状态之一:
- NEW:尚未启动的线程状态
- RUNNABLE:在Java虚拟机中执行的线程处于此状态。
- BLOCKED:被阻塞等待监视的线程处于此状态。
- WAITING:正在等待另一个线程执行特定动作的线程的状态。
- TIMED_WAITING:正在等待另一个线程执行动作达到指定等待时间的线程的状态。
- TERMINATED:已退出的线程处于的状态
//观察测试线程的状态
public class TestState {
public static void main(String[] args) {
Thread thread = new Thread(()-> {
for (int i = 0; i < 5; i++) {
new MySleep().Asleep(1000);
System.out.println("running....");
}
});
//1.观察线程NEW状态
Thread.State state = thread.getState();
System.out.println(state); //输出:NEW
//2.观察线程启动后状态
thread.start(); //启动线程
state = thread.getState();
System.out.println(state);
while(state != Thread.State.TERMINATED){ //只要线程不终止就一直输出状态
new MySleep().Asleep(500); //模拟延迟
state = thread.getState(); //更新状态
System.out.println(state); //打印状态
}
//thread.start(); //报错:java.lang.IllegalThreadStateException
//死亡之后的线程不能再启动
}
}
-线程的优先级
Java提供一个线程调度器来监控程序中启动后就进入状态的所有线程,线程调度器按照优先级决定应该调度哪一个线程来执行。线程优先级用数字表示,范围1~10
- Thread.MIN_PRIORITY = 1;
- Thread.MAX_PRIORITY = 10;
- Thread.NORM_PRIORITY =5;
可用getPriority()来获取优先级
可用setPriority(int xx)来设置优先级
//测试优先级
public class PriorityTest {
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);
Thread t6 = new Thread(myPriority);
//设置优先级再启动
t1.start();
t2.setPriority(4);
t2.start();
t3.setPriority(8);
t3.start();
t4.setPriority(Thread.MIN_PRIORITY); //MIN_PRIORITY = 1
t4.start();
t5.setPriority(Thread.MAX_PRIORITY); //MAX_PRIORITY = 10
t5.start();
t6.setPriority(Thread.NORM_PRIORITY); //NORM_PRIORITY = 5
t6.start();
//设置优先级高不一定就先执行,还是要看CPU的具体调度
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " >> " + Thread.currentThread().getPriority());
}
}
-守护线程 daemon
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
守护线程其实很多:后台记录操作日志,监控内存,垃圾回收等,都是守护线程
//守护线程测试 上帝守护你
public class DaemonTest {
public static void main(String[] args) {
//创建线程的实例对象
God god = new God();
Human human = new Human();
Thread thread = new Thread(god);
thread.setDaemon(true); //系统默认所有的线程都是用户线程,只有设置才能称为守护线程
thread.start();
new Thread(human).start(); //默认为用户线程
}
}
//上帝线程
class God implements Runnable{
@Override
public void run() {
while(true){ //上帝线程一直守护执行,没有尽头。
//但是设置守护线程之后,虚拟机就不会确保他是否执行完
System.out.println("God守护你!");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//人类线程
class Human implements Runnable{
@Override
public void run() {
for (int i = 0; i <= 36500; i++) { //人类的线程存活的时间有限,终究会执行完成
System.out.println("You are alive " + i + "Days");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("-=====Good Bye World!=====-"); //人类线程执行完成,退出程序
}
}