Java多线程04:线程的状态和方法
线程的状态
五种状态
观测线程状态
一个线程可以在给定的时间点处于一个状态,这些状态是不反映任何操作系统线程状态的虚拟机状态
getState()方法查看线程的状态
状态标识符 | 状态描述 |
---|---|
NEW | 尚未启动的线程处于此状态 |
RUNNABLE | 在Java虚拟机中执行的线程处于此状态 |
BLOCKED | 被阻塞等待监视器锁定的线程处于此状态 |
WAITING | 正在等待另一个线程执行特定动作的线程处于此状态 |
TIMED_WAITING | 正在等待另一线程执行动作达到指定等待时间的线程处于此状态 |
TERMINATED | 已退出的线程处于此状态 |
public class Main {
public static void main(String[] args) {
/**
* Lambda表达式直接创建Thread对象,不用实现Runnable接口
*/
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("这是run()方法");
});
/**
* getState()方法启动前观察状态(NEW)
*/
System.out.println(thread.getState());
/**
* 启动后观察状态(RUNNABLE)
*/
thread.start();
System.out.println(thread.getState());
/**
* getState()方法返回值是Thread.State类型
*/
while (thread.getState() != Thread.State.TERMINATED){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* 更新线程状态
*/
System.out.println(thread.getState());
}
}
}
线程的方法
线程停止
不建议使用destroy()、stop()等方法停止线程
建议使用标志位flag来让线程停止
public class Main implements Runnable {
/**
* 1、设置一个标志位
*/
boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("线程运行了" + i++ + "次");
}
}
/**
* 2、设置一个公开的方法停止线程,转换标志位
*/
public void stop(){
flag = false;
}
public static void main(String[] args) {
Main main = new Main();
Thread thread = new Thread(main);
thread.start();
for (int i = 0; i <= 1000; i++) {
System.out.println("main方法运行了" + i + "次" );
if (i == 900){
/**
* 调用stop()方法切换标志位,让线程停止
*/
main.stop();
System.out.println("该结束了");
break;
}
}
}
}
线程休眠
sleep()方法指定当前线程阻塞的毫秒数,时间达到后线程进入就绪状态
可以模拟网络延时、倒计时
每个对象都有一个锁,sleep()不会释放锁
练习:模拟延时
public class Main implements Runnable {
int num = 10;
@Override
public void run() {
while (true) {
if (num <= 0) {
break;
}
/**
* 模拟网络延时,可以放大问题的发生性(如线程不安全)
*/
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了第" + num-- +"张票");
}
}
public static void main(String[] args) {
Main main = new Main();
new Thread(main, "老师").start();
new Thread(main, "学生").start();
new Thread(main, "黄牛").start();
}
}
练习:打印当前系统时间
import java.time.LocalTime;
public class Main {
public static void TestSleep() throws InterruptedException {
for (int i = 0; i < 10; i++) {
LocalTime now = LocalTime.now();
System.out.print(now);
Thread.sleep(1000);
/**
* 刷新打印区
*/
System.out.print('\r');
}
}
public static void main(String[] args) throws InterruptedException {
TestSleep();
}
}
线程礼让
yield()方法让当前正在执行的线程暂停,但不阻塞,从运行状态转为就绪状态
礼让不一定成功,由CPU调度
public class Main implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程开始执行!");
/**
* yield()方法线程礼让
*/
Thread.yield();
System.out.println(Thread.currentThread().getName() + "线程结束!");
}
public static void main(String[] args) {
Main main = new Main();
new Thread(main, "学生").start();
new Thread(main, "老师").start();
}
}
线程强制执行
join()方法强制此线程执行完成后,再执行其他线程,其他线程都被阻塞
public class Main implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "线程强制执行" + i + "次");
}
}
public static void main(String[] args) throws InterruptedException {
Main main = new Main();
/**
* join()方法需要具体的对象名调用,因此显示创建线程对象
*/
Thread thread = new Thread(main, "VIP");
thread.start();
for (int i = 0; i < 100; i++) {
if (i == 10){
thread.join();
}
System.out.println("主线程执行" + i + "次");
}
}
}
线程优先级
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行
使用getPriority()和setPriority()方法获取或更改优先级,线程的优先级用数字表示,范围从1~10
优先级高的不一定先执行
public class Main implements Runnable{
@Override
public void run() {
System.out.println("线程优先级------>" + Thread.currentThread().getPriority());
}
public static void main(String[] args) {
Main main = new Main();
Thread thread1 = new Thread(main);
Thread thread2 = new Thread(main);
Thread thread3 = new Thread(main);
Thread thread4 = new Thread(main);
Thread thread5 = new Thread(main);
/**
* 先设置优先级,再启动
*/
thread1.setPriority(7);
thread1.start();
thread2.start();
/**
* 最小优先级Thread.MIN_PRIORITY=1
*/
thread3.setPriority(Thread.MIN_PRIORITY);
thread3.start();
thread4.setPriority(9);
thread4.start();
/**
* 最大优先级Thread.MAX_PRIORITY=10
*/
thread5.setPriority(Thread.MAX_PRIORITY);
thread5.start();
}
}
守护线程
线程分为用户线程和守护线程,虚拟机必须确保用户线程执行完毕,但不用等待守护线程执行完毕,如后台记录操作日志、监控内存、垃圾回收等待
setDaemon(true)方法设置进程为守护进程
public class Main {
public static void main(String[] args) {
Thread protect = new Thread(() -> {
while (true) {
System.out.println("这是守护进程");
}
});
Thread user = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("这是用户进程");
}
});
/**
* setDaemon(true)方法设置守护进程
* 用户进程结束后JVM就结束,不会等待守护进程结束
*/
protect.setDaemon(true);
protect.start();
user.start();
}
}