Java 中的线程

Thread 类与 Runnable 接口

Thread 中部分方法:

  • join():调用 join() 方法的 Thread 对象结束以前,当前线程一直处于等待状态,不会继续向前运行;内部是通过循环判断该 Thread 对象的 isAlive 方法返回 true 时,调用该 Thread 对象的 wait() 方法,该方法是属于 Object 的方法,且是由当前线程进行调用的,因此当前线程会处于等待状态;当调用 join() 方法的 Thread 对象结束后,会调用 notifyAll 方法通知处于等待状态的线程
1
2
3
4
5
6
7
8
9
10
11
12
public static void joinTest() {
for (int i = 0; i < 10; i++) {
int finalI = i;
final Thread thread = new Thread(() -> System.out.println(finalI));
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

输出: 0,1,2,3,4,5,6,7,8,9

  • setDaemon(): 线程的默认行为是,只要线程活着,进程就无法退出(普通的用户线程),守护线程不会阻止进程的退出;当应用程序的所有非守护线程均已经结束时,无论是否存在正在运行的守护线程,Java 程序将结束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void daemonTest() {
final Thread thread = new Thread(() -> {
while (true) {
System.out.println("true = " + true);
}
});
thread.setName("local-daemon-thread-20200204");
thread.setDaemon(true);
thread.start();

// 只要主线程的打印执行完毕,不管守护线程有没有在执行,整个执行都将结束
for (int i = 0; i < 100; i++) {
System.out.println("main thread = " + i);
}
}
  • setUncaughtExceptionHandler():线程因异常而退出时,默认的行为是打印线程的名称,异常类型,异常消息、堆栈打印;可以设置一个未捕获异常的处理器
1
2
3
4
5
6
7
8
9
public static void exceptionHandlerTest() {
final Thread thread = new Thread(() -> {
throw new IllegalArgumentException("illegal argument");
});
thread.setUncaughtExceptionHandler((t, e) -> {
System.out.printf("thread id: %s, thread name: %s, exception: %s", t.getId(), t.getName(), e);
});
thread.start();
}

多个 Thread 使用一个 Runnable 对象与每个 Thread 使用独立的 Runnable 对象的区别?