当前位置: 首页 > 科技观察

面试官:你了解过线程组和线程优先级吗?

时间:2023-03-21 22:45:54 科技观察

什么是线程组在Java中,一个线程组用ThreadGroup表示,Thread存放在线程组中,字面意思也很容易理解。在创建线程的过程中,Thread不能脱离线程组。之前我们学习创建线程的时候,并没有指定线程组,因为默认会使用当前线程环境作为线程组,可以通过Thread.currentThread().getThreadGroup()获取线程组,可以方便我们对线程的管理,一定程度上提高安全性。公共类ThreadGroupTest{publicstaticvoidmain(String[]args){newThread(()->{System.out.println(Thread.currentThread().getThreadGroup().getName());}).start();System.out.println(Thread.currentThread().getThreadGroup().getName());}}输出:在主线程组下可以找到mainmain;ThreadGroup是一个标准的“向下引用”树状结构,之所以这样设计是为了“防止‘上级’线程被‘下级’线程引用而不能被GC有效回收”。线程优先级线程的优先级由操作系统决定。不同的操作系统级别是不同的。Java中提供了1~10的等级范围供我们参考。Java默认的线程优先级是5,线程的执行顺序由调度器决定,线程的优先级会在线程被调用前设置好。源码说明:/***最低级别*/publicfinalstaticintMIN_PRIORITY=1;/***默认级别*/publicfinalstaticintNORM_PRIORITY=5;/***最高级别*/publicfinalstaticintMAX_PRIORITY=10;获取线程优先级publicstaticvoidmain(String[]args){newThread(()->{System.out.println("默认级别:{}"+Thread.currentThread().getPriority());}).start();}输出:默认级别:{}5设置级别publicstaticvoidmain(String[]args){Threadt=newThread(()->{System.out.println("默认级别:{}"+Thread.currentThread().getPriority());});t.开始();t.setPriority(10);}Output:defaultlevel:{}10一般来说,高级别的优先级往往会被执行的概率更高,注意这是一个概率问题,下面我们来测试一下:publicstaticvoidmain(String[]args){Threadt=newThread(()->{System.out.println("hello"+Thread.currentThread().getPriority());System.out.println("默认级别:{}"+Thread.currentThread().getPriority());});t.setPriority(3);苏氨酸eadt1=newThread(()->{System.out.println("你好"+Thread.currentThread().getPriority());System.out.println("默认级别:{}"+Thread.currentThread().getPriority());});t1.setPriority(7);Threadt2=newThread(()->{System.out.println("hello"+Thread.currentThread().getPriority());System.out.println("默认级别:{}"+Thread.currentThread().getPriority());});t2.setPriority(10);t.开始();t1.开始();t2.start();}第一次输出:hello7defaultlevel:{}7hello10defaultlevel:{}10hello3defaultlevel:{}3第二次:hello3defaultlevel:{}3hello7defaultlevel:{}7hello10defaultlevel:{}10第三次hello10defaultlevel:{}10hello7defaultlevel:{}7hello3defaultlevel:{}3...我发现经过不断的尝试,高阶出现的概率会更高,所以想用它来完成一些具体业务的同学已经注意到,不推荐使用它,也不靠谱。前面说过,底层还是由操作系统来调度。Java提供了一个“线程调度器”来监视和控制处于“RUNNABLE状态”的线程的调度策略,采用“抢占”的策略,优先级高的线程会比优先级低的线程有更大的机会率先执行。在优先级相同的情况下,按照“先到先得”的原则。每个Java程序都有一个默认的主线程,也就是JVM启动的第一个线程主线程。除了主线程之外,还有一个线程是守护线程,它的优先级比较低。如果所有非守护线程都终止,则守护线程将自动终止。可以用来实现一些特定的场景,比如手动关闭线程的场景。有些场景不关闭会造成资源浪费,手动关闭很麻烦。这里我们可以通过setDaemon(true)来指定。publicstaticvoidmain(String[]args){Threadt=newThread(()->{System.out.println("hello"+Thread.currentThread().getPriority());System.out.println("默认级别:{}"+Thread.currentThread().getPriority());});t.setDaemon(真);//默认为falset.setPriority(10);Threadt1=newThread(()->{System.out.println("hello"+Thread.currentThread().getPriority());System.out.println("默认级别:{}"+Thread.currentThread().getPriority());});t1.setPriority(7);t.开始();t1.start();}Output:hello7defaultlevel:{}7hello10defaultlevel:{}10发现即使指定了高级别,执行优先级仍然是线程组下的最低优先级我们都在下刚才是主线程组,那么线程组下的优先级怎么样呢?接下来测试一下:publicstaticvoidmain(String[]args){//指定线程组,名字为g1ThreadGroupgroup=newThreadGroup("g1");group.setMaxPriority(4);Threadt=newThread(group,()->{System.out.println("你好"+Thread.currentThread().getP优先事项());System.out.println("默认级别:{}"+Thread.currentThread().getPriority());},"t0");t.setPriority(10);t.开始();}Output:hello4defaultlevel:{}4发现在g1线程组下指定最大优先级后,线程t0的最大优先级只能是4,所以这也是使用线程组的好处我们可以通过以下方式复制线程组,ThreadGroup提供了enumerate方法:publicstaticvoidmain(String[]args)throwsInterruptedException{//指定名为g1的线程组ThreadGroupgroup=newThreadGroup("g1");团体。设置最大优先级(4);Threadt=newThread(group,()->{System.out.println("hello"+Thread.currentThread().getPriority());System.out.println("默认级别:{}"+Thread.currentThread().getPriority());},"t0");t.setPriority(10);t.开始();//复制线程组System.out.println(group.activeCount());//1Thread[]list=newThread[group.activeCount()];组。枚举(列表);线程.睡眠(3000);System.out.println(列表[0].getName());//输出t0}统一异常捕获publicstaticvoidmain(String[]args){//指定名为g1的线程组ThreadGroupgroup=newThreadGroup("g1"){//统一异常捕获publicvoiduncaughtException(Threadt,可抛e){System.out.println(t.getName()+":"+e.getMessage());//t0:我犯了一个错误}};group.setMaxPriority(4);Threadt=newThread(group,()->{System.out.println("hello"+Thread.currentThread().getPriority());System.out.println("默认级别:{}"+Thread.currentThread().getPriority());thrownewRuntimeException("我犯了一个错误");},"t0");t.setPriority(10);t.开始();}向下引用的树状数据结构线程组不仅可以放线程,其实还可以放其他线程组,看源码定义publicstaticvoidmain(String[]args){//指定名为g1的线程组ThreadGroupgroup=newThreadGroup("g1"){//统一异常捕获publicvoiduncaughtException(Threadt,Throwablee){System.out.println(t.getName()+":"+e.getMessage());//t0:我犯了一个错误}};group.setMaxPriority(4);Threadt=newThread(group,()->{System.out.println("你好"+Thread.currentThread().getPriority());System.out.println("默认级别:{}"+Thread.currentThread().getPriority());thrownewRuntimeException("我错了");},"t0");t.setPriority(10);t.开始();}这里可以大胆猜猜为什么要用这个数据结构?其实你通过源码发现里面很多地方都调用了checkAccess方法,尤其是在set操作中,字面意思就是检查是否有权限,我看这个方法publicfinalvoidcheckAccess(){SecurityManagersecurity=System.getSecurityManager();if(security!=null){security.checkAccess(this);它调用一个SecurityManager,它是Java的安全管理器,它允许应用程序在执行之前确定潜在的不安全或敏感操作是什么,以及它是否在允许它执行的安全上下文中执行。应用程序可能允许也可能不允许此操作。总的来说,就是为了保证安全。通过上面的了解,我们应该知道为什么要用这种树结构了。层层控制,方便管理,提高安全性,出现问题也能快速定位。就像公司的人事组织架构一样,一切都是为了把公司管理好。结语本文内容到这里就结束了,大家一定要自己多了解,不要死记硬背。