线程
2025-01-22 08:19:30    1.2k 字   
This post is also available in English and alternative languages.

线程是一个操作系统级别的概念。Java语言(包括其他编程语言)本身不创建线程;而是调用操作系统层提供的接口创建、控制、销毁线程实例。

不同的操作系统(Windows/Unix/Linux/其他),它们所支持的线程底层实现和操作效果也是不尽相同的;不过一个操作系统支持的线程至少会有四种状态:就绪、执行、阻塞和终结。线程在四种状态下进行切换,都是要消耗不少的CPU计算能力的

线程还分为用户线程和操作系统线程:

  • 操作系统线程(内核线程),是指操作系统内核为了完成硬件接口层操作,由操作系统内核创建的线程:例如I/O操作的内核线程,这些线程应用程序是不能干预的
  • 用户线程,是指用户安装/管理的应用程序,为执行某一种操作,而由这个应用程序创建的线程(Java线程,都是用户级线程)。

sleep将“当前线程”进入阻塞状态,并且不会释放这个线程所占用的任何对象锁的独占状态


1. 线程中断

1.1. interrupt相关方法

结论先行:单纯用 interrupt() 方法并不能中断(停止)当前正在运行的线程,需要配合其他方法才能正确中断(停止)线程

  • Thread.currentThread().interrupt():设置线程中断(停止)标识;
  • Thread.interrupted():判断线程的中断(停止)标识。

如果使用interrupt方法只是设置线程的中断(停止)标识,线程内部需要手动判断标识(interrupted方法),组合使用才能中断(停止)线程的处理;
如果只调用interrupt方法,是不会起到中断(停止)线程的目的。

  • 只调用interrupt方法,不会起到中断(停止)线程的目的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /**
    * @author yxcheng
    */
    @Slf4j
    public class TestApp {
    public static void main(String[] args) throws Exception {

    Thread thread1 = new Thread(() -> {
    for (int i = 0; i < 200000; i++) {
    log.info("threadName:[{}],i:[{}]", Thread.currentThread().getName(), i);
    }
    });

    thread1.start();

    TimeUnit.MILLISECONDS.sleep(500);

    //设置 thread1 的中断(停止)标识
    thread1.interrupt();

    //等待 thread1 执行结束
    thread1.join();

    log.warn("----- end -----");
    }
    }

    运行结果:

    1
    2
    3
    4
    2022-07-07 14:08:45.853 default [Thread-0] INFO  org.concurrent.demo01.TestApp - 22 - threadName:[Thread-0],i:[199997]
    2022-07-07 14:08:45.853 default [Thread-0] INFO org.concurrent.demo01.TestApp - 22 - threadName:[Thread-0],i:[199998]
    2022-07-07 14:08:45.853 default [Thread-0] INFO org.concurrent.demo01.TestApp - 22 - threadName:[Thread-0],i:[199999]
    2022-07-07 14:08:45.853 default [main] WARN org.concurrent.demo01.TestApp - 36 - ----- end -----
  • interruptinterrupted 两个方法,组合使用中断(停止)处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    /**
    * @author yxcheng
    */
    @Slf4j
    public class TestApp {
    public static void main(String[] args) throws Exception {

    Thread thread1 = new Thread(() -> {
    // for循环,循环时判断thread1的中断(停止)标识
    for (int i = 0; !Thread.currentThread().isInterrupted() && i < 200000; i++) {
    log.info("threadName:[{}],i:[{}]", Thread.currentThread().getName(), i);
    }
    });

    thread1.start();

    TimeUnit.MILLISECONDS.sleep(500);

    //设置 thread1 的中断(停止)标识
    thread1.interrupt();

    //等待 thread1 执行结束
    thread1.join();

    log.warn("----- end -----");
    }
    }

    运行结果:

    1
    2
    3
    4
    5
    ........
    2022-07-07 14:07:12.048 default [Thread-0] INFO org.concurrent.demo01.TestApp - 18 - threadName:[Thread-0],i:[24103]
    2022-07-07 14:07:12.048 default [Thread-0] INFO org.concurrent.demo01.TestApp - 18 - threadName:[Thread-0],i:[24104]
    2022-07-07 14:07:12.048 default [Thread-0] INFO org.concurrent.demo01.TestApp - 18 - threadName:[Thread-0],i:[24105]
    2022-07-07 14:07:12.049 default [main] WARN org.concurrent.demo01.TestApp - 36 - ----- end -----

2. 线程阻塞

通过LockSupport#parkLockSupport#unpark方法配合使用,可以让线程暂停、恢复。

  • LockSupport#park:阻塞(暂停)线程
  • `LockSupport#unpark:唤醒(恢复)线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* @author yxcheng
*/
@Slf4j
public class TestApp {
public static void main(String[] args) throws Exception {

Thread thread1 = new Thread(() -> {
log.info("线程:[{}],开始执行",Thread.currentThread().getName());

// 阻塞、挂起 线程
LockSupport.park();

log.info("线程:[{}],被唤醒了", Thread.currentThread().getName());
log.info("线程:[{}],结束执行", Thread.currentThread().getName());
});

thread1.start();
TimeUnit.MILLISECONDS.sleep(500);

log.info("主线程:[{}] 执行中", Thread.currentThread().getName());

// 唤醒 thread1
LockSupport.unpark(thread1);

//主线程等待 thread1 执行结束
thread1.join();

log.info("主线程:[{}] 执行结束", Thread.currentThread().getName());
}
}

运行结果:

1
2
3
4
5
2022-07-07 14:55:26.623 default [Thread-0] INFO  org.concurrent.demo01.TestApp - 17 - 线程:[Thread-0],开始执行
2022-07-07 14:55:27.128 default [main] INFO org.concurrent.demo01.TestApp - 31 - 主线程:[main] 执行中
2022-07-07 14:55:27.128 default [Thread-0] INFO org.concurrent.demo01.TestApp - 22 - 线程:[Thread-0],被唤醒了
2022-07-07 14:55:27.129 default [Thread-0] INFO org.concurrent.demo01.TestApp - 24 - 线程:[Thread-0],结束执行
2022-07-07 14:55:27.130 default [main] INFO org.concurrent.demo01.TestApp - 39 - 主线程:[main] 执行结束

3. Reference