线程和进程

进程:操作系统资源资源分配的基本单位,占用的资源较大,进程间无共享内存,切换进程时,cpu 消耗太多

线程:任务调度和执行的基本单位,一个进程可以有多个线程,线程之间公用所在进程的内存,资源共享。创建线程的开销较小。

线程的生命周期

20190923200503282

线程总共有 6 种状态,分别如下:

  1. 新建状态(NEW):当创建一个线程对象的时候,线程处于该状态。

  2. 运行状态(RUNABLE):当调用线程的 start 方法时,线程处于该状态。该状态下有 2 个不同的子状态,分别是可运行和运行状态,当 cpu 调度当前线程的时候,线程状态为可运行状态,当 cpu 放弃当前线程或者当前线程执行 yield 操作时,该线程会重新进入可运行状态,等待 cpu 调度。

  3. 等待状态(WAITING 和 TIME_WAITING):两个状态唯一的区别就是是否加上时间参数,通过调用 sleep,join,wait 等方法进入该状态。

  4. 阻塞状态(BLOCKED):只有在执行到 synchronized 代码块,没有获取到锁的时候,会变成阻塞状态。

  5. 结束状态(TERMINATED):当前线程执行结束。

线程的创建方式

  1. 继承 Thread

  2. 实现 Runnable 接口

  3. 实现 fature/callable 接口,带返回值的线程

  4. 从线程池中获取

线程的中断

如何正确停止一个线程,在 java 中,有提供 stop,destory,suspend,resume 方法,但是这些方法都已经被不推荐使用了。原因是强行终止一个线程,可能会导致当前线程里面的资源没有来得及释放,比如锁等等。这样会导致程序出现异常。

那么如何优雅的停止线程呢,可以通过 jdk 提供的 interrupt 标示来实现,jdk 在 native 中维护了 interrupt 标示来判断当前线程是否能够继续执行

  1. 线程内部通过 isInterrupted 方法判断是否中断,调用方通过 interrupt 方法终止指定线程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public static void  test1() throws InterruptedException {
    Thread t1 = new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
    i++;
    }
    System.out.println("当前线程被中断,累计的和为:"+i);
    }, "t1");
    t1.start();
    TimeUnit.SECONDS.sleep(1);
    t1.interrupt();
    }

    输出结果:

    20190923210241748

  2. 同样在调用方调用 interrupt 中断程序之后,然后在线程中执行 Thread.interrupted()重新将标示改成 false

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     public static void  test2() throws InterruptedException {
    Thread t1 = new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
    System.out.println("线程执行中。。。");
    }
    System.out.println("线程被中断");
    Thread.interrupted();

    System.out.println("线程中断标示复位,当前标志为:"+Thread.currentThread().isInterrupted());
    }, "t1");
    t1.start();
    TimeUnit.SECONDS.sleep(1);
    t1.interrupt();
    }

    image-20210311194747418

  3. 线程中 catch 了 InterruptedException,然后在线程结束之前做一些资源处理

    public static void test3() throws InterruptedException {
    Thread t1 = new Thread(() -> {

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
            while (true) {
    try {
    System.out.println("线程执行中。。。");
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    System.out.println("线程被中断");
    System.out.println("对于中断之后抛出的异常可以进行相应的处理");
    }
    }
    }, "t1");
    t1.start();
    TimeUnit.SECONDS.sleep(1);
    t1.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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class Test {

public static void main(String[] args) {
new Thread(() -> {
while (true){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t1").start();


new Thread(() -> {
while (true){
synchronized (Test.class){
try {
//调用wait方法必须处于同步代码块中
Test.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}
},"t2").start();

new Thread(new BlockDemo(),"blocked-1").start();
new Thread(new BlockDemo(),"blocked-2").start();
}


static class BlockDemo extends Thread{
@Override
public void run() {
synchronized (BlockDemo.class){
while (true){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}

进入命令行,输入 jps 查看所有正在进行的程序

image-20210311194918584

当前正在测试的程序为 Test,并且端口号为 12320,执行命令 jstack 12320 查看该端口下所有线程的运行状态。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
lingfandeMacBook-Pro:thread-demo lingfan$ jstack 12320
2019-09-23 20:15:25
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode):

"Attach Listener" #18 daemon prio=9 os_prio=31 tid=0x00007fc7dd003800 nid=0x5903 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"DestroyJavaVM" #17 prio=5 os_prio=31 tid=0x00007fc7dd9d6000 nid=0x1803 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"blocked-2" #16 prio=5 os_prio=31 tid=0x00007fc7dd9d5800 nid=0x5803 waiting for monitor entry [0x0000700006ae4000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.example.threaddemo.Test$BlockDemo.run(Test.java:47)
- waiting to lock <0x000000076b157f78> (a java.lang.Class for com.example.threaddemo.Test$BlockDemo)
at java.lang.Thread.run(Thread.java:748)

"blocked-1" #14 prio=5 os_prio=31 tid=0x00007fc7dc050000 nid=0xa603 waiting on condition [0x00007000069e1000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at com.example.threaddemo.Test$BlockDemo.run(Test.java:47)
- locked <0x000000076b157f78> (a java.lang.Class for com.example.threaddemo.Test$BlockDemo)
at java.lang.Thread.run(Thread.java:748)

"t2" #12 prio=5 os_prio=31 tid=0x00007fc7dd9a4800 nid=0xa803 in Object.wait() [0x00007000068de000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076acec9f8> (a java.lang.Class for com.example.threaddemo.Test)
at java.lang.Object.wait(Object.java:502)
at com.example.threaddemo.Test.lambda$main$1(Test.java:27)
- locked <0x000000076acec9f8> (a java.lang.Class for com.example.threaddemo.Test)
at com.example.threaddemo.Test$$Lambda$2/1237514926.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)

"t1" #11 prio=5 os_prio=31 tid=0x00007fc7dd002800 nid=0xa903 waiting on condition [0x00007000067db000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at com.example.threaddemo.Test.lambda$main$0(Test.java:15)
at com.example.threaddemo.Test$$Lambda$1/625576447.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)

"Service Thread" #10 daemon prio=9 os_prio=31 tid=0x00007fc7dd99f800 nid=0x4003 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #9 daemon prio=9 os_prio=31 tid=0x00007fc7de008800 nid=0x4103 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #8 daemon prio=9 os_prio=31 tid=0x00007fc7de008000 nid=0x4303 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=31 tid=0x00007fc7dd99f000 nid=0x4503 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=31 tid=0x00007fc7dd99e000 nid=0x4603 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"Monitor Ctrl-Break" #5 daemon prio=5 os_prio=31 tid=0x00007fc7dd99c800 nid=0x3c03 runnable [0x00007000060c6000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x000000076adcb058> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
- locked <0x000000076adcb058> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)

"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007fc7df00a000 nid=0x3a03 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007fc7de80c800 nid=0x3503 in Object.wait() [0x0000700005ec0000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076ab08ec8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x000000076ab08ec8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007fc7de001000 nid=0x3403 in Object.wait() [0x0000700005dbd000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076ab06b68> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x000000076ab06b68> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"VM Thread" os_prio=31 tid=0x00007fc7dd804000 nid=0x4f03 runnable

t1 线程执行 sleep 代码,状态为 java.lang.Thread.State: TIMED_WAITING (sleeping)。

t2 线程执行 wait 代码,状态为 java.lang.Thread.State: WAITING (on object monitor)。

blocked-1 线程抢夺到 synchronized 的锁,状态为 java.lang.Thread.State: TIMED_WAITING (sleeping)。
blocked-2 线程没抢夺到 synchronized 的锁,状态为 java.lang.Thread.State: BLOCKED (on object monitor)。