JavaWeb笔记04:中断/线程状态转换

中断/线程状态转换

1 设置普通状态位让线程停止:
public class Main {
    private static boolean condition = true;

    static class work 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 work());
        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后,他会执行完当前循环才会停止。

2 JAVA内部的中断:

public void interrupt(): 中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位。

public static boolean interrupted():判断当前线程的中断标志位是否设置,调用后清除标志位(静态方法),清除标志位是为了不影响后续的通知。(推荐使用)
public boolean isInterrupted() :判断对象关联的线程的标志位是否设置,调用后不清除标志位

Thread.interrupted();//静态方法,调用后会清除标志位。
t.isInterrupted();//t线程调用后,不会清除标志位。

通过interrupt设置中断:

public class Main {
    static class work 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 work());
        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异常,通过在catch中添加break来处理这个中断通知。

  • 而run()中没有sleep类时,和普通设置true/false中断没有区别。即interrupt既可以应对普通情况,又可以应对像sleep这种特殊情况。

  • 可以通过Thread.interrupted()current.isInterrupted()来判断是否设置了停止标志位

3 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(主动放弃)是还在就绪态,只不过是将优先级降到最低了,先等待其他线程执行结束。
4 线程的状态获取:

枚举:
枚举类似类,一个枚举可以拥有成员变量,成员方法,构造方法。
一个enum的构造方法限制是private的,也就是不允许我们调用。枚举类详情

enum Gender{
男,女
}
Gender gender = Gender.;

线程的状态通过枚举保存。

Thread.State[] values = Thread.State.values();

for(Thread.State state:values){
System.out.println(state);
}

得到线程的6个状态:

NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
5 线程状态和线程状态转移:
(1)线程状态转移

初始:NEW :刚创建好一个线程对象,但还没有调用start方法,不具备争夺CPU的条件。

运行:RUNNABLE: 线程创建好之后,其他线程调用了该对象的start()方法。具备争夺CPU的条件,可运行于线程池中,等待被线程调度选中,获取cpu的使用权,此时处于就绪状态(raady)。就绪状态的线程在获得cpu时间片后变为运行中状态(running)。

不再拥有抢占CPU的资格:

  • 阻塞:BLOCKED:线程因锁而堵塞,BLOCKED是在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态。
  • 等待:WAITING:进入该状态的线程需要等待其他线程做出一些特定的动作(通知或中断)
  • 超时等待:TIMED_WAITING:该状态不同于WAITING,它可以在指定的时间内自行返回

终止:TERMINATED: 线程运行结束,但线程对象还在,即run()结束后就会进入该状态。 如:t.join()后代表线程结束了,此时状态为TERMINATED。
线程状态转换
详细流程如下:
在这里插入图片描述

注意:

  • Java中将运行状态和就绪态统称为RUNNABLE,而要细分的话,要分为Ready和Running.

  • t.start()后线程主要在RUNNABLE状态上。

(2)线程的核心方法
  • Thread.sleep(long millis): 当前线程调用此方法会进入TIME_WAITING状态,但不释放对象锁,millis后线程自动苏醒进入就绪状态。作用:给其它线程执行机会的最佳方式。
  • Thread.yield():当前线程调用此方法放弃获取的cpu时间片,由运行状态变会就绪状态,让OS再次选择线程。作用:让相同优先级的线程轮流执行,但并不保证一定会轮流执行。实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。Thread.yield()不会导致阻塞。
  • t.join():当前线程里调用其它线程t的join方法,当前线程进入WAITING或TIME_WAITING(t.join(long mills)可指定超时时间millis)状态,当前线程不释放已经持有的对象锁。线程t执行完毕或者millis时间到,当前线程进入就绪状态。
  • obj.wait():当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列WAITING或TIME_WAITING(wait可指定超时时间)。依靠notify()/notifyAll()唤醒或者wait(long timeout)timeout时间到自动唤醒。
  • obj.notify() 、 obj.notifyAll():唤醒在此对象监视器上等待的单个线程,选择是任意性的。notifyAll()唤醒在此对象监视器上等待的所有线程。唤醒后不保证马上能够执行,因为需要等待CPU调度,从就绪态转为运行态。

参考博客:https://www.cnblogs.com/cowboys/p/9315331.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值