线程组
- 可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程。这样的组织结构有些类似于树的形式。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a2c07197eddc23f855f10b1b0c82dc06.png#pic_center)
- 线程组的作用是,可以批量的管理线程或线程组对象,有效地对线程或线程组对象进行组织。
线程对象关联线程组 (一级管关联)
- 所谓的1级关联就是父对象中有子对象,但并不创建子孙对象。这种情况经常出现在开发中,比如创建一些线程时,为了有效地对这些线程进行组织管理,通常的情况下是创建一个线程组,然后再将部分线程归属到该组中。这样的处理可以对零散的线程对象进行有效的组织与规划。
- 演示
public class Demo1 {
public static void main(String[] args) {
Runnable runnableA = new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + " " +
Thread.currentThread().getThreadGroup().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable runnableB = new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + " " +
Thread.currentThread().getThreadGroup().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
ThreadGroup threadGroup = new ThreadGroup("Listen的Group");
Thread a = new Thread(threadGroup, runnableA, "A");
Thread b = new Thread(threadGroup, runnableB, "B");
System.out.println(Thread.currentThread().getName() + " " +
Thread.currentThread().getThreadGroup().getName());
a.start();
b.start();
}
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/31b145dbddcbc8cf5dc581672e76e05d.png#pic_center)
- 所谓的多级关联就是父对象中有子对象,子对象中再创建子对象,也就是出现子孙对象的效果了。但是此种写法在开发中不太常见,如果线程树结构设计得非常复杂反而不利于线程对象的管理
- 线程组有自动归属的特性, 就是如果你在主线程main中创建一个线程组, 即使你不把他归属到main这个线程组中, 他也会自动归属.
线程组的批量停止
- 通过将线程归属到线程组中,当调用线程组ThreadGroup的interrupt(方法时,可以将该组中的所有正在运行的线程批量停止。
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
Runnable runnableA = new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + " " +
Thread.currentThread().getThreadGroup().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
};
Runnable runnableB = new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + " " +
Thread.currentThread().getThreadGroup().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
};
ThreadGroup threadGroup = new ThreadGroup("Listen的Group");
Thread a = new Thread(threadGroup, runnableA, "A");
Thread b = new Thread(threadGroup, runnableB, "B");
System.out.println(Thread.currentThread().getName() + " " +
Thread.currentThread().getThreadGroup().getName());
a.start();
b.start();
Thread.sleep(3000);
System.out.println(threadGroup.getName() + " 线程打断");
threadGroup.interrupt();
}
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/fbebe186a9b35c3e237975f3c0edf2b8.png#pic_center)
线程中出现异常的统一处理
指定线程对象进行异常统一处理
- 下面代码程序运行后在控制台输出空指针异常。在Java的多线程技术中,可以对多线程中的异常进
行“捕捉”,使用的是UncaughtExceptionHandler类,从而可以对发生的异常进行有效的处理。 - 演示
public class Demo3 {
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
threadA.setName("A");
threadA.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println(ThreadA.currentThread().getName() + " 抛出了异常");
}
});
threadA.start();
}
}
class ThreadA extends Thread {
@Override
public void run() {
String s = null;
s.getBytes();
}
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/3aa563faf30a963715db93644e25dcaf.png#pic_center)
- 方法setUncaughtExceptionHandler()的作用是对指定的线程对象设置默认的异常处理器。
指定线程类的所有线程对象进行异常统一处理
- 方法setUncaughtExceptionHandler()是给指定线程对象设置的异常处理器。在Thread类中还可以使用setDefaultUncaughtExceptionHandler()方法对所有线程对象设置异常处理器。
- 演示
public class Demo4 {
public static void main(String[] args) {
ThreadB.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName() + " 出现异常我捕获了");
}
});
ThreadB threadB = new ThreadB();
threadB.setName("B");
ThreadB threadB1 = new ThreadB();
threadB1.setName("BB");
threadB.start();
threadB1.start();
}
}
class ThreadB extends Thread {
@Override
public void run() {
String s = null;
s.getBytes();
}
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/2f14b1bd2632a2b1e940534fdd59fdc3.png#pic_center)
- 方法setDefaultUncaughtExceptionHandler()的作用是为指定线程类的所有线程对象设置默认的异常外理器。
线程组内异常处理器
public class Demo5 {
public static void main(String[] args) {
ThreadGroup group = new ThreadGroup("Listen的group") {
@Override
public void uncaughtException(Thread t, Throwable e) {
super.uncaughtException(t, e);
System.out.println(t.getName() + " 出现异常我捕获了");
}
};
MyThread[] myThreads = new MyThread[5];
for (int i = 0; i < 5; i++) {
myThreads[i] = new MyThread(group, "线程" + i, "" + i);
myThreads[i].start();
}
MyThread myThread = new MyThread(group, "出错线程001", "ab");
myThread.start();
}
}
class MyThread extends Thread {
private String num;
public MyThread(ThreadGroup group, String name, String num) {
super(group, name);
this.num = num;
}
@Override
public void run() {
int num = Integer.parseInt(this.num);
while (true) {
System.out.println(Thread.currentThread().getName() + " 死循环中");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/52a79168bebec3b569874a67e3155286.png#pic_center)
- 从运行的结果来看,在默认的情况下和给了统一异常处理下,线程组中的一个线程出现异常不会影响其他线程的运行。
- 需要注意的是 使用自定义java.lang.ThreadGroup线程组,并且重写uncaughtException方法处理组内线程中断行为时,每个线程对象中的run()方法内部不要有异常catch语句,如果有catch语句, 则public void uncaughtException (Thread t, Throwablee)方法不执行。
线程异常处理的传递
- 首先在run方法看有没有catch语句, 如果没有, 就在看这个线程对象有没有异常处理器, 再看这个线程类有没有统一异常处理, 最后再看这个线程组有没有统一异常处理器.