多线程 2

1. Thread 类、常见方法

1.1 常用构造方法

方法 说明
Thread() 创建线程对象
Thread( Runnable target) 使用 Runnable 对象创建线程对象
Thread(String name) 创建线程对象并命名
Thread( Runnable target ,String name) 使用 Runnable 对象创建线程对象,并命名

1.2 线程的常见属性

属性 获取方法
ID getId()
名称 getNname()
状态 getState()
优先级 getPriority()
是否是后台线程 isDaemon()
是否存活 isAlive()
是否中断 isInterrupted()

获取线程的名称

java 复制代码
Thread t1 = new Thread();
//给线程起名字
Thread t2 = new Thread("线程2");
Thread t3 = new Thread(new Runnable(){
    @Override
    public void run(){
    }
},"线程3");
//getName 获取线程的名字
System.out.println(t1.getName());
System.out.println(t2.getName());
System.out.println(t3.getName());

线程的名字默认是 Thread - 数字, 给线程起名字,可以在线程数量很多的情况下,更方便地观察线程

1.3 前台线程和后台线程

  • 前台线程 : 会阻止进程的结束
  • 后台线程 : 不会阻止进程的结束
java 复制代码
public static void main(String[] args) throws InterruptedException {
   Thread t = new  Thread(() -> {
        for (int i = 0; i < 5; i++) {
            System.out.println("thread");
            try {
            		// 睡眠 1 秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println("t线程结束");
    });
    t.start();
    // 睡眠 1 秒
    Thread.sleep(1000);
    System.out.println("主线程结束");
    // main 和 t 都是前台线程 2 个线程都结束 进程才结束
}

进程默认就是前台线程,可以通过 setDaemon(true) 把线程设置为 后台线程

参数是 true 表示是后台线程, 默认是 false 表示前台线程; 要在线程开启前设置

java 复制代码
public static void main(String[] args) throws InterruptedException {
    Thread t = new  Thread(() -> {
        for (int i = 0; i < 5; i++) {
            System.out.println("thread");
            try {
            		// 睡眠 1 秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println(" t 线程结束");
    });
    // 在 strat() 开始前 把 t 设置成 后台线程(守护线程)
    t.setDaemon(true);
    t.start();
    // 睡眠 1 秒
    Thread.sleep(1000);
    System.out.println("主线程结束");
    // 前台线程结束了 进程就结束
}

1.4 start( )

strart() 会调用操作系统的 API , 在操作系统中创造出一个线程

Java为了让一个 thread 对象和 一个操作系统线程 一一对应, 每个线程只能调用一次 start()

java 复制代码
public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        System.out.println("t1 thread");
    });
    t1.start();
    t1.start();
}

1.5 中断线程

中断线程的 2 种方式 :

  • 通过共享标记进行沟通
  • 通过调用 interrupt( ) 方法
使用自定义变量作为标识位
java 复制代码
private static boolean running = true;
public static void main(String[] args) {
    Thread t = new Thread(() -> {
        while(running){
            System.out.println("thread t");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    });
    t.start();
    try {
    	//睡眠 4 秒后 中断线程
          Thread.sleep(4000);
          running = false;
    }catch (InterruptedException e) {
          throw new RuntimeException(e);
    }
}
使用 interrupt( )
java 复制代码
public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread(() -> {
    	// currentThread 获取 t 线程的引用
        Thread cur = Thread.currentThread();
        //isInterrupted 判断 t 线程的标识位
        while (!cur.isInterrupted()) {
            System.out.println("thread");
            try {
            	//预计 sleep 100 秒
                Thread.sleep(100_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    t.start();
    Thread.sleep(1000);
    // 设置 t 线程的标识位
    t.interrupt();
}

interrupt() 能设置标志位,还能唤醒 sleep 等导致线程堵塞的方法

Q :为什么这里会在线程中止后又打印 thread ?

A : interrupt() 设置标识位为 true 唤醒 sleep() ,让 sleep() 抛出异常后, sleep() 自动重新设置标识位为 false
Thread.currentThread() : 获取当前线程的引用

java 复制代码
public static void main(String[] args) {
//获取主线程的引用
  Thread mainThread = Thread.currentThread();
  System.out.println(mainThread.getName());
}

如果在主线程执行 Thread.currentThread() 就是获取主线程的引用;

在thread1线程中执行 Thread.currentThread() 就是获取thread1线程的引用

1.6 join( ) 线程等待

java 复制代码
private static int sum = 0;
public static void main(String[] args) {
    Thread t = new Thread(() -> {
        for (int i = 1; i <= 1000; i++) {
            sum += i;
        }
    });

    t.start();
    System.out.println("sum = " + sum);
}

要求是 :等 t 线程计算完 1~1000 的和之后, 主线程再进行打印和

结果是 t线程还没有计算, 主线程就打印结果了,如果使用 sleep() 让 主线程睡一会,睡少了 t 线程还没有计算完,睡多了又浪费时间,另外如果 t 线程的逻辑复杂, sleep() 就更不适用,这时使用 join() 就能让一个线程执行结束后,再继续执行

方法 说明
join() 当前线程一直等待,直到目标线程执行完毕才继续
join( long millis ) 当前线程最多等待 millis 毫秒,超时后无论目标线程是否结束,当前线程都会继续执行
java 复制代码
private static int sum = 0;
public static void main(String[] args) throws InterruptedException {
   Thread t = new Thread(() -> {
       for (int i = 1; i <= 1000; i++) {
           sum += i;
       }
   });
   t.start();
   t.join();
   System.out.println("sum = " + sum);
}

join() 如果目标线程一直不结束,那就会一直等下去

java 复制代码
public static void main(String[] args) throws InterruptedException {
	//获取 main 线程的引用
     Thread main = Thread.currentThread();
     System.out.println("开始等待");
     main.join();
     System.out.println("线程结束");
}

join( long millis ) 等待设置的 ms 后继续执行

java 复制代码
public static void main(String[] args) throws InterruptedException {
	//获取 main 线程的引用
     Thread main = Thread.currentThread();
     System.out.println("开始等待");
     //等待 2 秒
     main.join(2000);
     System.out.println("线程结束");
 }

如果调用 join 前线程就已经执行完了,再次调用 join 是线程不会堵塞

2. 线程的状态

线程的 6 种状态

状态 表示
NEW 创建了 Thread 对象但没有 start()
TERMINATED 操作系统线程销毁(线程的执行入口执行完了),但 thread 对象还在
RUNNABLE 可运行的 1.CPU 正在执行 2.等待CPU调度执行(就绪)
WAITING 线程无限等待 调用无参 join(),目标线程不结束,等待进程的状态
TIMED_WAITING 线程有限等待 调用join(long millis) 过程中,等待进程的状态
BLOCKED 由于锁导致的堵塞
NEW 、RUNNABLE 、TERMINATED 状态的转换
java 复制代码
public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread(() -> {
        
    });
    System.out.println(t.getState());
    t.start();
    System.out.println(t.getState());
    t.join();
    System.out.println(t.getState());
}
WAITING
java 复制代码
public static void main(String[] args) throws InterruptedException {
     Thread mainThread = Thread.currentThread();
     Thread t = new Thread(() -> {
         while(true){
             System.out.println("mainThread state " + mainThread.getState());
         }
     });
     t.start();
     t.join();
 }
TIMED_WAITING
java 复制代码
public static void main(String[] args) throws InterruptedException {
    Thread mainThread = Thread.currentThread();
    Thread t = new Thread(() -> {
        while(true){
            System.out.println("mainThread state " + mainThread.getState());
        }
    });
    t.start();
    t.join(10000);
}
相关推荐
hhhjhl15 分钟前
Undici 跨端三方库仓颉适配全流程
java·开发语言·ubuntu
wangchunyu11425 分钟前
JAVA JVM内存结构与运行时数据区
java·开发语言·jvm
光锥智能1 小时前
海康机器人举行2026移动机器人新品发布会:箱式存拣升级,「明智」系列发布
java·前端·机器人
行思理1 小时前
Nginx 跨站请求(CORS)配置完全指南:从原理到生产实践
java·前端·nginx
小溪学编程1 小时前
Spring @Bean 与 @Component 注解的区别详解
java·后端·spring
Wang's Blog2 小时前
Java 项目实战: 交友项目 - 圈子互动章总结与自检清单
java·bootstrap·交友
xyouyuweizhu2 小时前
字节流与字符流:Java IO 的两条主线该怎么选
java·开发语言·python
代码方舟2 小时前
零信任架构实战:基于天远人企关联构建自动化供应链核心企业关联穿透与利益冲突审查网关
java·人工智能·架构·自动化
liyi_hz20083 小时前
O2OA(翱途) V10.1 即将发布|功能再升级,安全再加固,协同更高效!
java·javascript·windows·开源软件
骑着蜗牛撵大象3273 小时前
AI Agent 工程化开发实战(三):用 StateGraph 给智能体搭一条可回放的状态流水线
java·开发语言·jvm·ai·状态管理·langgraph·stategraph