相关概念

  • 进程
  • 线程—单线程/多线程
  • 并发—单核CPU实现多任务
  • 并行—同一时刻,多个任务同时执行。多核CPU可以实现并行

一个程序启动时,即一个进程启动以后,会默认启动一个主线程(main),可以在主线程中创建子线程Thread1,Thread2,也可以在子线程中继续创建子线程,
主线程的生命周期和子线程不一定相同,可能主线程已经结束了,子线程还在继续执行。
同一个应用程序可以有多个进程,和多个线程

创建线程

  • 创建线程的两种方式
    a. 继承Thread

    1. class A extends Thread{
    2. @Override
    3. public void run() {
    4. //do something
    5. }
    6. }
    7. }
  • b. 实现Runnable—由于Java中不支持多继承,如果一个类A已经继承了其他的类,如果A还想继续在里面实现多线程,则无法继承Thread来实现,这时候可以使用Runnable

    1. class A extends B implements Runnable{
    2. @Override
    3. public void run() {
    4. //do something
    5. }
    6. }
    7. }
  • 这两种方式本质上没有区别,都是走的start0()函数,Runnable更加适合多个线程共享一个资源的情况,避免单继承的限制

【Java】 线程 thread - 图1

售票系统

线程退出(中断线程)

  • 通知方式
  1. public class ThreadExitDemo {
  2. public static void main(String[] args) throws InterruptedException {
  3. MyThread myThread = new MyThread();
  4. myThread.start();
  5. //休眠10秒,通知线程退出
  6. Thread.sleep(5000);
  7. //通知线程退出
  8. myThread.setLoop(false);
  9. }
  10. }
  11. class MyThread extends Thread {
  12. //提供方法用于外部来通知线程内部退出
  13. public void setLoop(boolean loop) {
  14. this.loop = loop;
  15. }
  16. //设置一个控制变量
  17. private boolean loop = true;
  18. @SneakyThrows
  19. @Override
  20. public void run() {
  21. while (loop) {
  22. Thread.sleep(50);
  23. System.out.println("====");
  24. }
  25. }
  26. }
  1. 线程常用方法
  • setName
  • getName
  • start—底层调用run()方法,run方法本身不会创建线程,run()里面调用的start0()会开启线程,由CPU决定如何调度
  • run
  • setPriority
  • getPriority
  • interrupt—中断线程,没有正真结束线程,一般用于中断正在休眠的线程
  • sleep
  • yield—让出CPU供其他线程执行,不一定成功
  • join—线程插队 在主线程中执行t.goin(),则表示先执行完子线程在回到主线程中继续执行
  1. package com.example.usage;
  2. import lombok.SneakyThrows;
  3. /**
  4. * @author chenzhian
  5. * @description 线程常用方法示例
  6. * @date 2021年05月07日 15:08
  7. */
  8. public class ThreadMethodDemo {
  9. public static void main(String[] args) throws InterruptedException {
  10. // 调用对方的join方法
  11. T t = new T();
  12. t.start();
  13. for (int i = 0; i < 10; i++) {
  14. Thread.sleep(1000);
  15. System.out.printf("[主线程] %s 正在做事 %d \n", Thread.currentThread().getName(), i);
  16. // 主线程执行到第5个时,让出CPU资源,让子线程执行完我再继续执行
  17. if (i == 5) {
  18. System.out.println("干大事的先来...");
  19. // 关键方法--这里让t执行完毕
  20. t.join();
  21. // Thread.yield();//不一定能让成功
  22. System.out.println("现在又轮到主线程继续干事情了");
  23. }
  24. }
  25. }
  26. }
  27. class T extends Thread {
  28. @SneakyThrows
  29. @Override
  30. public void run() {
  31. for (int i = 0; i < 20; i++) {
  32. Thread.sleep(500);
  33. System.out.printf("[子线程] %s 干了 %d 件大事 \n", Thread.currentThread().getName(), i);
  34. }
  35. }
  36. }

守护线程

守护线程示例

  1. package com.example.usage;
  2. import lombok.SneakyThrows;
  3. /**
  4. * @author chenzhian
  5. * @description 守护线程示例--主线程退出以后,守护线程自动结束
  6. * @date 2021年05月07日 15:58
  7. */
  8. public class DaemonThreadDemo {
  9. public static void main(String[] args) throws InterruptedException {
  10. MyDaemonThread myDaemonThread = new MyDaemonThread();
  11. // [1] 设置为守护线程
  12. myDaemonThread.setDaemon(true);
  13. myDaemonThread.start();
  14. for (int i = 0; i < 10; ++i) {
  15. Thread.sleep(1000);
  16. System.out.printf("宝宝玩了 %d 个小时了 \n", i);
  17. }
  18. }
  19. }
  20. class MyDaemonThread extends Thread {
  21. @SneakyThrows
  22. @Override
  23. public void run() {
  24. // 无限循环
  25. for (; ; ) {
  26. Thread.sleep(1000);
  27. System.out.println("爸爸妈妈在看着孩子");
  28. }
  29. }
  30. }

线程状态/生命周期

【Java】 线程 thread - 图2

【Java】 线程 thread - 图3

  1. public class ThreadLifeScopeDemo {
  2. public static void main(String[] args) throws InterruptedException {
  3. T2 t = new T2();
  4. System.out.printf("[%s] --> %s \n", t.getName(), t.getState());
  5. t.start();
  6. while (Thread.State.TERMINATED != t.getState()) {
  7. System.out.printf("[%s] --> %s \n", t.getName(), t.getState());
  8. Thread.sleep(500);
  9. }
  10. // 主线程休眠10秒,通知线程退出
  11. Thread.sleep(5000);
  12. // 通知线程退出
  13. t.setLoop(false);
  14. System.out.printf("[%s] --> %s \n", t.getName(), t.getState());
  15. }
  16. }
  17. class T2 extends Thread {
  18. // 设置一个控制变量
  19. private boolean loop = true;
  20. // 提供方法用于外部来通知线程内部退出
  21. public void setLoop(boolean loop) {
  22. this.loop = loop;
  23. }
  24. @SneakyThrows
  25. @Override
  26. public void run() {
  27. while (true) {
  28. for (int i = 0; i < 10; ++i) {
  29. System.out.println("test Thread State");
  30. Thread.sleep(500);
  31. }
  32. //for循环以后退出
  33. break;
  34. }
  35. }
  36. }

输出:

  1. [Thread-0] --> NEW
  2. [Thread-0] --> RUNNABLE
  3. test Thread State
  4. test Thread State
  5. [Thread-0] --> RUNNABLE
  6. test Thread State
  7. [Thread-0] --> RUNNABLE
  8. test Thread State
  9. [Thread-0] --> RUNNABLE
  10. test Thread State
  11. [Thread-0] --> RUNNABLE
  12. test Thread State
  13. [Thread-0] --> RUNNABLE
  14. test Thread State
  15. [Thread-0] --> RUNNABLE
  16. test Thread State
  17. [Thread-0] --> RUNNABLE
  18. test Thread State
  19. [Thread-0] --> RUNNABLE
  20. test Thread State
  21. [Thread-0] --> RUNNABLE
  22. [Thread-0] --> TERMINATED
  23. Process finished with exit code 0

线程同步—Synchronized

当一个线程在对内存进行操作时,其他线程不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能够对该地址进行操作

【Java】 线程 thread - 图4

互斥锁&死锁

【Java】 线程 thread - 图5

【Java】 线程 thread - 图6

【Java】 线程 thread - 图7

  1. 线程死锁
  2. 释放锁

【Java】 线程 thread - 图8