# 1.自然结束
能自然结束的话,尽量让一个线程自然结束。
# 2.配合自定义volatile标志位
# 示例: volatile stop
// volatile保证可见性
private static volatile boolean isStopped = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (!isStopped) {
// 事实上,synchronized的调用会导致本地内存同步
// println中调用了synchronized,此时将isStopped的volatile去除
// 该线程依然可以正常退出
System.out.println("Do something");
}
System.out.println("Thread exited");
});
thread.start();
Thread.sleep(1000);
isStopped = true;
}
// Do something
// Do something
// Do something
// Do something
// Thread exited
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 缺点
循环期间或线程执行中做了阻塞操作,不能及时查询volatile标志位,导致线程结束延迟。
# 2.使用Interrupt
# Thread中与interrupt相关的三个方法
//t.interrupt() 实际上只是设置t线程的打断标志位为true,并不是直接打断线程的运行
public void interrupt()
//t.isInterrupted() 仅返回当前线程的打断标志位
public boolean isInterrupted()
//Thread.interrupted() 返回当前线程的打断标志位,并将该标志位复位,即重新设置为false
public static boolean interrupted()
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# interrupt与sleep(), wait(), join()
sleep()方法在睡眠的时候,不到时间是没有办法叫醒的,这个时候可以用interrupt设置标志位,然后需要catch InterruptedException来进行处理,决定继续睡或者是执行其他逻辑。
注意,在catch到该异常时,中断标志位已经由JVM复位。
# 示例: 打断sleep()
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("Interrupted: " + Thread.currentThread().isInterrupted());
}
});
thread.start();
thread.interrupt();
}
//Interrupted: false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
注意,interrupt()不能中断正在竞争synchronized锁的线程。
如果希望在竞争锁的阻塞状态下可以被打断,需要使用ReentrantLock的lockInterruptibly()
# 示例: lockInterruptibly()
static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
lock.lock();
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
t1.start();
Thread.sleep(1000);
Thread t2 = new Thread(() -> {
System.out.println("t2 started");
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
System.out.println("t2 interrupted");
} finally {
try {
lock.unlock();
} catch (Exception e) {
}
}
System.out.println("t2 ended");
});
t2.start();
Thread.sleep(1000);
t2.interrupt();
}
// t2 started
// t2 interrupted
// t2 ended
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
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