1 线程的五大状态 & 线程方法

本文视频截图均来自【狂神说 Java】B 站视频

线程的五大状态
image.png
image.png

线程方法
image.png

2 线程操作

2.1 线程停止

  • 不推荐使用 JDK 提供的stop(), destroy()方法(已废弃
  • 推荐让线程自己停下来
  • 建议使用一个标志位来终止线程,如当flag=false时,终止线程

2.2 线程休眠 sleep

  • sleep()单位为毫秒
  • sleep()存在InterruptedException异常,需要try-catch或者抛出异常(Idea 里面会自动识别并建议你这么做)
  • sleep()后线程进入就绪状态
  • 每一个对象都有一个锁,**sleep()**不会释放锁。

2.3 线程让出 CPU yield

  • yield()让线程进入就绪状态
  • **yield()**不一定能让出 CPU,但是否延迟执行,由 CPU 调度决定

2.4 线程强制执行 join

  • 如果子线程使用join(),则主线程需要等待子线程结束后才能执行
  • join()可以实现线程的插队

    1. public class MyThread implements Runnable {
    2. @Override
    3. public void run() {
    4. for (int i = 0; i < 5; i++) {
    5. System.out.println(Thread.currentThread().getName() + " ==> " + i);
    6. try {
    7. Thread.sleep(1000);
    8. } catch (InterruptedException e) {
    9. throw new RuntimeException(e);
    10. }
    11. }
    12. }
    13. public static void main(String[] args) {
    14. MyThread myThread = new MyThread();
    15. Thread t1 = new Thread(myThread, "Child thread");
    16. t1.start();
    17. for (int i = 0; i < 5; i++) {
    18. System.out.println("Main thread ==> " + i);
    19. try {
    20. // 子线程通过 join 插队
    21. if (i == 2) {
    22. try {
    23. t1.join();
    24. } catch (InterruptedException e) {
    25. throw new RuntimeException(e);
    26. }
    27. }
    28. Thread.sleep(1000);
    29. } catch (InterruptedException e) {
    30. throw new RuntimeException(e);
    31. }
    32. }
    33. }
    34. }

执行结果:

  1. Main thread ==> 0
  2. Child thread ==> 0
  3. Main thread ==> 1
  4. Child thread ==> 1
  5. Main thread ==> 2
  6. Child thread ==> 2
  7. Child thread ==> 3
  8. Child thread ==> 4
  9. Main thread ==> 3
  10. Main thread ==> 4

2.5 观测线程状态

image.png

  • BLOCKED阻塞状态:等待锁
  • NEW新生状态:刚被创建,但还没有运行
  • RUNNABLE就绪状态:Java 中为正在执行的线程
  • TERMINATED终止状态:已经退出的线程
  • TIMED_WAITING等待时间状态:正在等待另一个线程执行动作到达指定等待时间
  • WAITING等待动作状态:正在等待另一个线程执行特定动作
  1. public class TestState {
  2. public static void main(String[] args) {
  3. Thread thread = new Thread(()->{
  4. System.out.println("Thread starts...");
  5. for (int i = 0; i < 2; ++i) {
  6. try {
  7. Thread.sleep(1000);
  8. } catch (InterruptedException e) {
  9. throw new RuntimeException(e);
  10. }
  11. }
  12. System.out.println("Thread terminating...");
  13. });
  14. Thread.State state = thread.getState();
  15. System.out.println(state); // NEW
  16. thread.start();
  17. state = thread.getState();
  18. System.out.println(state); // RUNNABLE
  19. while (state != Thread.State.TERMINATED) {
  20. try {
  21. Thread.sleep(100);
  22. } catch (InterruptedException e) {
  23. throw new RuntimeException(e);
  24. }
  25. state = thread.getState();
  26. System.out.println(state); // TIMED_WAITING or TERMINATED
  27. }
  28. }
  29. }

退出之后的线程不能再启动,即处于TERMINATED状态的线程不能再执行start()

3 守护线程

  • 线程分为用户线程和守护线程
  • 虚拟机必须保证用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕
    • e.g. 后台记录操作日志、监控内存、垃圾回收
  1. public class TestDaemon implements Runnable {
  2. @Override
  3. public void run() {
  4. while (true) {
  5. System.out.println("Daemon running...");
  6. try {
  7. Thread.sleep(1);
  8. } catch (InterruptedException e) {
  9. throw new RuntimeException(e);
  10. }
  11. }
  12. }
  13. public static void main(String[] args) {
  14. // 守护线程 daemon
  15. Thread daemonThread = new Thread(new TestDaemon());
  16. daemonThread.setDaemon(true); // 设置守护线程
  17. daemonThread.start();
  18. // 用户线程 user
  19. Thread userThread = new Thread(() -> {
  20. for (int i = 0; i < 10; i++) {
  21. System.out.println("User running...");
  22. try {
  23. Thread.sleep(5);
  24. } catch (InterruptedException e) {
  25. throw new RuntimeException(e);
  26. }
  27. }
  28. });
  29. userThread.start();
  30. }
  31. }

执行结果:

  1. Daemon running...
  2. Daemon running...
  3. ...
  4. User running...
  5. Daemon running...
  6. Daemon running...
  7. ...
  8. Daemon running...
  9. Daemon running...
  10. User running...
  11. Daemon running...
  12. Daemon running...
  13. Daemon running...
  14. Daemon running...
  15. Daemon running...
  16. Daemon running...

可以发现,在 User 线程结束后,守护线程又运行了一段时间才终止的。说明 Java 虚拟机并没有立即退出。