设置普通状态位让线程停止:
public class
普通状态位的方式通知停止 {
private static boolean condition = true;
static class 写作业 implements Runnable {
@Override
public void run() {
while (condition) {
try {
System.out.println("写第一份作业");
Thread.sleep(3 * 1000);
System.out.println("写第二份作业");
Thread.sleep(3 * 1000);
System.out.println("写第三份作业");
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
break;
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new 写作业());
t.start();
Scanner scanner = new Scanner(System.in);
scanner.nextLine();
System.out.println("准备通知停止写作业");
condition = false; // 不具备让 A 的 sleep 抛异常的功能
System.out.println("已经通知停止写作业");
t.join();
System.out.println("已经停止写作业");
}
}
注意:
使用普通状态位通知线程中断,当线程处于sleep中时,线程不会立即停止,condition变为false后,他会执行完当前任务才会停止。
JAVA内部的中断:
public void interrupt():
中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位
public static boolean interrupted():
判断当前线程的中断标志位是否设置,调用后清除标志位(静态方法),清除标志位是为了不影响后续的通知。(推荐使用)
public boolean isInterrupted() :
判断对象关联的线程的标志位是否设置,调用后不清除标志位
Thread.interrupted();//静态方法,调用后会清除标志位。
t.isInterrupted();//t线程调用后,不会清除标志位。
通过interrupt设置中断:
public class 如何通知一个线程停止 {
static class 写作业 implements Runnable {
@Override
public void run() {
Thread t = Thread.currentThread();
while (!t.isInterrupted()) {
try {
System.out.println("写第一份作业");
Thread.sleep(3 * 1000);
System.out.println("写第二份作业");
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
// 通过这里捕获异常处理停止操作
break;
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new 写作业());
t.start();
Scanner scanner = new Scanner(System.in);
scanner.nextLine();
System.out.println("准备通知停止写作业");
t.interrupt();
System.out.println("已经通知停止写作业");
t.join();
System.out.println("已经停止写作业");
}
}
注意:
-
当任务run()中含有sleep类时,interrupt调用结束之后,线程内会收到一个异常
InterruptedException,
但此时t.isInterrupted仍是false.我们可以捕获InterruptedException异常,来处理这个中断通知。 -
而run()中没有sleep类时,和普通设置true/false中断没有区别。即interrupt既可以应对普通情况,又可以应对像sleep这种特殊情况。
-
可以通过
Thread.interrupted()
或current.isInterrupted()
来判断是否设置了停止标志位
Thread 的常见操作:
1) 启动线程 start:把线程放到就绪队列中,拥有争夺CPU的资格
2) 中断线程interrupt: 通知线程停止
3) join 等待一个线程停下来
4) 强制停止
currentThread():
public static Thread currentThread();
返回当前线程对象的引用
Thread t = Thread.currentThread();
join():
public void join()
等待线程结束
public void join(long millis)
等待线程结束,最多等millis 毫秒
public void join(long millis, int nanos)
同理,但可以更高精度
yield():
Thread.yield()
; 主动放弃CPU,但保留争夺CPU的资格,即优先让其他线程执行,前面没有其他线程时,再继续执行。
sleep():
public static void sleep(long millis) throws InterruptedException
休眠当前线程millis 毫秒
public static void sleep(long millis, int nanos) throws InterruptedException
可以更高精度的休眠
java中各种各样的sleep:
public static void main(String[] args) throws InterruptedException {
Thread.sleep(10); // 毫秒
TimeUnit.DAYS.sleep(10); // 天
TimeUnit.HOURS.sleep(10); // 小时
}
注意:
- Thread.sleep(毫秒):休眠—当前线程放弃CPU,把状态修改,x毫秒后,重新进入就绪态。进入就绪态后需要重新争夺CPU,所以,sleep的时间>=x毫秒,不是一个精确的x毫秒
- sleep是放弃抢占CPU,退出就绪态,而yield(主动放弃)是还在就绪态,只不过是将优先级降到最低了,先等待其他线程执行结束。
线程的状态获取:
枚举:
enum Gender{
男,女
}
Gender gender = Gender.男;
线程的状态通过枚举保存。
Thread.State[] values = Thread.State.values();
for(Thread.State state:values){
System.out.println(state);
}
线程状态和线程状态转移:
NEW:刚创建好,不具备争夺CPU的条件
RUNNABLE: 具备争夺CPU的条件(Ready),已经在CPU上了(Running); t.start()后主要在这个状态上(RUNNABLE)。
TERMINATED: 线程运行结束,但线程对象还在,即run()结束后就会 进入该状态。 如:t.join()后代表线程结束了,此时状态为TERMINATED。
BLOCKED、WAITING、TIMED_WAITING: 不再拥有抢占CPU的资格
注意:
- Java中将运行状态和就绪态统称为RUNNABLE,而要细分的话,要分为Ready和Running.