JAVA 多线程问题,主线程没有阻塞,为什么会等待子线程退出 java 1.8

发布于 2022-09-12 22:24:11 字数 2888 浏览 14 评论 0

学习多线程过程中,想测试isDeamon方法,但是我发现对于子线程没有设置为守护线程时,这个主线程还是会等待子线程执行完毕再结束,很奇怪,我在主线程中也没有阻塞代码,且第一时间打印了最后main方法中main done的消息,那应该可以结束了吧。

package runnable;

public class RunnableTest {
    public static int flag = 0;
 public static void main(String[] args){
        Thread.currentThread().setPriority(10);
 // 设置默认的异常处理器,全局的, 每个线程可以定义自己的默认处理器
 Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
 public void uncaughtException(Thread t, Throwable e) {
                System.out.println(t.toString() + "found exception: " + e.toString());
 }
        });
 Thread t1 = new Thread(new NewMyRunnable("t1"));
 // 设置线程的名字
 t1.setName("My Test 1");
 // 设置当该线程由于未捕获的异常而突然终止时调用的处理程序
 t1.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
 public void uncaughtException(Thread t, Throwable e) {
                System.out.println(t.toString() + "found exception: " + e.toString());
 }
        });
 t1.setPriority(1);
 System.out.println(t1.toString()+t1.isDaemon());
 Thread t2 = new Thread(new NewMyRunnable("t2"));
 // 更改此线程的优先级。 数字越大优先级越高,优先处理,但是并不是一定优先
 t2.setPriority(5);
 t2.setName("My Test 2");
 System.out.println(t2.toString()+t2.isDaemon());
 Thread t3 = new Thread(new NewMyRunnable2("t3"));
 // 更改此线程的优先级。 数字越大优先级越高,优先处理,但是并不是一定优先 范围1-10
 t3.setPriority(5);
 t3.setName("My Test 3");
 System.out.println(t3.toString()+t3.isDaemon());
 t1.start();
 t2.start();
 t3.start();
 /*try {
 // 当前线程暂停执行,参数为毫秒
 Thread.sleep(1000); // 当前线程暂停执行,参数为毫秒,第二参数为纳秒,用于更高精度的停止
 Thread.sleep(1000, 100); } catch (InterruptedException e) { e.printStackTrace(); }*/ System.out.println("main done "+flag);
 }
}
class NewMyRunnable implements Runnable {
    private String name = "";
 public static int TIMES = 10;
 public NewMyRunnable(String name) {
        this.name = name;
 }
    @Override
 public void run() {
        int i = 0;
 try {
            Thread.sleep(100000);
 } catch (InterruptedException e) {
            e.printStackTrace();
 }
        while(i < TIMES){
            if(i==TIMES-1){
                throw new IllegalArgumentException("参数错误");
 }
            //RunnableTest.flag ++;
 //System.out.println(name+": "+RunnableTest.flag); System.out.println(name +": "+ i);
 // 提示调度器,我已经完成了重要工作,愿意切换线程(提示性非强制)
 Thread.yield();
 i++;
 }
    }
}
class NewMyRunnable2 implements Runnable {
    private String name = "";
 public static int TIMES = 10;
 public NewMyRunnable2(String name) {
        this.name = name;
 }
    @Override
 public void run() {
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
 public void uncaughtException(Thread t, Throwable e) {
                System.out.println("self defined "+t.toString() + "found exception: " + e.toString());
 }
        });
 throw new IllegalArgumentException("参数错误");
 }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

执笏见 2022-09-19 22:24:11

复制粘贴运行:

Thread[My Test 1,1,main]false
Thread[My Test 2,5,main]false
Thread[My Test 3,5,main]false
main done 0
self defined Thread[My Test 3,5,main]found exception: java.lang.IllegalArgumentException: 参数错误

可以看到主线程已经结束了……

玩心态 2022-09-19 22:24:11

这是JVM规定的.有线程执行就不会退出, 除了daemon 线程.

你的笑 2022-09-19 22:24:11

这是控制台打印结果:

Thread[My Test 1,1,main]false
Thread[My Test 2,5,main]false
Thread[My Test 3,5,main]false
main done 0
self defined Thread[My Test 3,5,main]found exception: java.lang.IllegalArgumentException: 参数错误
self defined Thread[My Test 2,5,main]found exception: java.lang.IllegalArgumentException: 参数错误
Thread[My Test 1,1,main]found exception: java.lang.IllegalArgumentException: 参数错误

接下来,一步一步分析下。
首先,主线程启动,并启动定义的3个子线程。但是以下代码都是由主线程输出的:

Thread[My Test 1,1,main]false
Thread[My Test 2,5,main]false
Thread[My Test 3,5,main]false
main done 0

说明主线程已执行完毕退出。
接下来看3个子线程。My Test 3和My Test 2的优先级比My Test 1要高,而My Test 2 需要 sleep 100000毫秒。因此My Test 3最先打印出以下代码,并执行完毕退出:

self defined Thread[My Test 3,5,main]found exception: java.lang.IllegalArgumentException: 参数错误

这里需要注意,My Test 3打印出来的代码是在NewMyRunnable2中定义的全局默认异常Thread.setDefaultUncaughtExceptionHandler中打印的,不是主线程中定义的全局默认异常输出的。因为主线程中的全局默认异常定义已经被NewMyRunnable2中的定义覆盖了。
接下来My Test 2的sleep时间到了,输出代码:

self defined Thread[My Test 2,5,main]found exception: java.lang.IllegalArgumentException: 参数错误

这里需要注意,My Test 2是NewMyRunnable的实例。而NewMyRunnable中并没有定义全局默认异常,那这行self defined……是从哪来的呢?是从NewMyRunnable2中的全局默认异常定义输出的。但是前边说了,My Test 3已经执行完毕退出了。查看setDefaultUncaughtExceptionHandler的文档可以看到这样的描述:

Uncaught exception handling is controlled first by the thread, then by the thread's ThreadGroup object and finally by the default uncaught exception handler.
意思是说:未捕获异常处理首先由线程控制,然后由线程的ThreadGroup对象控制,最后由默认的未捕获异常处理程序控制。

这样解释就通了。
接下来,轮到My Test 1执行了,并打印出如下代码:

Thread[My Test 1,1,main]found exception: java.lang.IllegalArgumentException: 参数错误

这行是由My Test 1线程自己定义的未捕获异常处理器输出的。

到此,整个程序执行完毕。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文