线程(一)线程基础

1. 线程创建、启动、运行

1.1 继承线程重写 run() 方法

java 复制代码
    static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("1. 继承 Thread 重写 run 方法,Thread implements Runnable");
        }
    }

    public static void main(String[] args) {
        new MyThread().start();
    }

1.2 新建线程传入 Runnable

java 复制代码
public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("2. 新建 Thread 传入 Runnable");
        }
    }).start();
}

2.线程状态

  • id:存储线程的唯一标识符,自增值,不能指定

  • name:存储线程的名字,不同线程名字可以相同,可以默认生成,也可以指定

    • 默认值:Thread_ + 自增值 ,该自增值与 id 自增值不同
  • priority:线程对象的优先级,默认一般为 5,范围为 1~10,属性值与父属性值相同,优先级并不会保证按照其优先级高低的顺序运行

  • daemon:是不是守护线程,默认为 false,守护线程会在主线程退出前结束,而非守护线程即便主线程退出了也仍然会执行,默认情况下父线程是守护线程,子线程也是守护线程。

  • status:线程状态

    • 该属性保存了线程的状态。在Java中,线程有6种状态------Thread.State枚举中定义这些状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED。这些状态的具体意义如下。

      • NEW:线程已经创建完毕但未开始执行
      • RUNNABLE:线程正在执行
      • BLOCKED:线程处于阻塞状态,发起了一个阻塞 I/O 或者申请了一个由其他线程占有的资源(例如锁),处于该状态的线程并不会占用 CPU 资源
      • WAITING:线程在等待另一个线程到达某种状态,例如 Object.wait()、Thread.join()、LockSupport.park(Object)。对应的能够使线程从 WAITING 状态变为 RUNNABLE 的方法包括:Object.notify()/notifyAll()和 LockSupport.unpark(Object)
      • TIMED_WAITING:该状态与 WAITING 类似,但是差别在于 TIMED_WAITING 会等待一定的时间,如果一定时间内没有被唤醒自动变为 RUNNABLE,sleep() 也会使线程进入这个状态。
      • TERMINATED:线程执行完毕。
    • (引用自:Java多线程编程实战指南(核心篇))

3.线程方法

方法 功能
static Thread currentThread() 返回当前线程
void run() 线程的执行逻辑
void start() 启动线程,只有该方法才会真正创建操作系统级别的线程。只能被调用一次,多次调用抛异常。
void join() 等待相应线程结束,例如线程 A 调用线程 B 的 join 方法,那么线程 A 会被暂停直到 B 执行结束。
static void yield() 使当前线程放弃一次对处理器的占用
static void sleep(long millis) 使当前线程停止运行指定时间

4.线程中断

有时我们需要终止某一个线程所执行的任务,需要用到线程中断

java 复制代码
        Thread thread = new Thread(() -> {
            for (int i = 0; i < Integer.MAX_VALUE; i++) {
                System.out.println(String.format("thread is interrupted count = %s, isInterrupted = %s", i, Thread.currentThread().isInterrupted()));
            }
        });

        thread.start();

        System.out.println("thread status : " + thread.getState());
        System.out.println("thread is interrupt : " + thread.isInterrupted());
        System.out.println("thread is live : " + thread.isAlive());

        Thread.sleep(20);
        System.out.println("thread interrupt ------------------------------------");
        thread.interrupt();

        System.out.println("thread status : " + thread.getState());
        System.out.println("thread is interrupt : " + thread.isInterrupted());
        System.out.println("thread is live : " + thread.isAlive());

thread status : RUNNABLE

thread is interrupt : false

thread is live : true

thread is interrupted count = 0, isInterrupted = false

thread is interrupted count = 1, isInterrupted = false

thread is interrupted count = 2, isInterrupted = false

...

thread is interrupted count = 157, isInterrupted = false

thread interrupt ------------------------------------

thread is interrupted count = 158, isInterrupted = false

thread status : RUNNABLE

thread is interrupt : true

thread is live : true

thread is interrupted count = 159, isInterrupted = true

thread is interrupted count = 160, isInterrupted = true

thread is interrupted count = 161, isInterrupted = true

thread is interrupted count = 162, isInterrupted = true

...

上述例子的结果看即便线程被中断,并且中断状态为 true ,但是线程仍然存活。并且正常执行,这并不是预期中的行为。

所以通过 interrupt() 方法并不能实现真正的中断。

  • 如果被中断线程在调用 wait()/join()/sleep() 方法被阻塞时调用中断将会抛出 InterruptedException 异常,中断状态被清除
  • 如果被中断线程在对 InterruptibleChannel 进行 I/O 操作被阻塞时,那么通道将会被关闭,同时设置中断状态抛出 ClosedByInterruptException 异常
  • 如果该线程被阻塞在 java.nio.channels.Selector 中,那么它将会被立即返回,同时设置中断状态

中断未存活的线程不产生任何影响。

如果想要真正的停止线程可以调用已经被废弃的方法 stop()

5.线程本地变量-ThreadLocal

在某些场景下,我们希望线程自己维护一套数据自己的环境变量

java 复制代码
        ThreadLocal<String> threadLocal = new ThreadLocal<>();

        for (int i = 0; i < 100; i++) {
            final int threadIndex = i;
            new Thread(() -> {
               threadLocal.set(Thread.currentThread().getName());

                try {
                    Thread.sleep(threadIndex * 10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(threadIndex + ":" + threadLocal.get());

            }, "thread-" + i).start();
        }

0:thread-0

1:thread-1

2:thread-2

3:thread-3

4:thread-4

...

96:thread-96

97:thread-97

98:thread-98

99:thread-99

可以看到每个线程维护的变量不冲突。

ThreadLocal 的原理是每个线程自己维护一个 Map ,Map 的 key 为 ThreadLocal ,val 为线程在 ThreadLocal 中存储的值。这样每个线程单独维护的 Map 就不会有并发冲突。

ThreadLocal 提供了 remove() 方法,用于删除 ThreadLocal 中当前线程的本地变量,如果本地变量无用时记得清除避免内存泄漏。

Java并发API中提供的InheritableThreadLocal类能够实现从线程的创建线程上继承本地变量的功能。如果线程A有一个线程本地变量,它又创建了线程B,那么线程B也拥有了与A相同的线程本地变量。

应用:

实际开发中,有很多需要用到用户信息的逻辑,例如某些场景需要校验用户是否登陆/用户权限等,但是传入 userId 对业务逻辑侵入性很大,此时就可用 ThreadLocal 在 web 容器入口处写入 user 信息,这样业务逻辑就不用一直传递 userId。在 web 容器执行完一次请求后清除 ThreadLocal 的数据避免造成影响。

6.线程工厂

工厂模式是一种用来创造实例的设计模式,使用工厂模式来创造线程具有以下优点。

  • 可以对同一个类型的线程创建做限制,例如最多可以创建多少个实例
  • 可以给同一个类型的线程创建做统计或者打标记,例如记录线程创建频次数量为线程名字添加固定前缀+自增值便于排查问题
java 复制代码
    class MyThreadFactory implements ThreadFactory {
        int count = 0;
        List<String> status = new ArrayList<String>();

        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread("thread-" + count++);
            status.add(thread.getName());
            return thread;
        }
    }
相关推荐
书源丶41 分钟前
三十六、File 类与 IO 流基础——文件操作的「第一步」
java
刀法如飞1 小时前
Go数组去重的20种实现方式,AI时代解决问题的不同思路
后端·算法·go
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题】【Java基础篇】第30题:JDK动态代理和CGLIB动态代理有什么区别
java·开发语言·后端·面试·代理模式
swipe1 小时前
别再把 AI 聊天做成纯文本:从 agui 这个前后端项目,拆解“可感知工具调用”的流式 AI UI
后端·langchain·llm
GetcharZp1 小时前
GitHub 爆火!纯 Go 编写的文件同步神器 Syncthing,凭什么成为程序员的标配?
后端
hERS EOUS1 小时前
SpringBoot 使用 spring.profiles.active 来区分不同环境配置
spring boot·后端·spring
DFT计算杂谈2 小时前
wannier90 参数详解大全
java·前端·css·html·css3
LucianaiB2 小时前
我用飞书多维表做了一个 AI 活动推荐智能体:每天自动催我别错过截止日期!
后端
marsh02062 小时前
43 openclaw熔断与降级:保障系统在异常情况下的可用性
java·运维·网络·ai·编程·技术
张健11564096482 小时前
临界区和同一线程上锁
java·开发语言·jvm