您现在的位置是:亿华云 > 应用开发
面试官:有了解过线程组和线程优先级吗?
亿华云2025-10-09 12:53:18【应用开发】7人已围观
简介什么是线程组在Java中,线程组使用ThreadGroup表示,其中Thread存于线程组中,从字面意思也很好理解。在创建线程过程中,Thread不能独立于线程组之外,之前我们学习创建线程时,没有指定
在Java中,线程组使用ThreadGroup表示,解过级其中Thread存于线程组中,线程线程从字面意思也很好理解。组和在创建线程过程中,优先Thread不能独立于线程组之外,面试之前我们学习创建线程时,没有指定线程组,解过级因为在默认情况下,线程线程它会将当前的组和线程环境作为线程组, 可以通过Thread.currentThread().getThreadGroup()获取线程组,线程组可以方便管理我们的线程,一定程度上提高了安全性。优先
public class ThreadGroupTest {
public static void main(String[] args) {
new Thread(() -> {
System.out.println(Thread.currentThread().getThreadGroup().getName());
}).start();
System.out.println(Thread.currentThread().getThreadGroup().getName());
}
}输出:
main
main可以发现在main线程组下;
ThreadGroup是面试一个标准的「向下引用」的树状结构,这样设计的解过级原因是「防止"上级"线程被"下级"线程引用而无法有效地被GC回收」。
线程优先级线程的线程线程优先级级别由操作系统决定,不同的组和操作系统级别是不一样的,在Java中,优先提供了一个级别范围1~10,方便我们去参考。Java默认的线程优先级为5,线程的执行顺序由调度程序来决定,线程的优先级会在线程被调用之前设定。云南idc服务商
源码描述:/
*** 最低级别
*/
public final static int MIN_PRIORITY = 1;
/
*** 默认级别
*/
public final static int NORM_PRIORITY = 5;
/
*** 最高级别
*/
public final static int MAX_PRIORITY = 10;获取线程优先级别public static void main(String[] args) {
new Thread(() -> {
System.out.println("default level: { }" + Thread.currentThread().getPriority());
}).start();
}输出: default level: { }5
设置级别public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("default level: { }" + Thread.currentThread().getPriority());
});
t.start();
t.setPriority(10);
}输出: default level: { }10
通常来讲,高级别的优先级往往会更高几率的执行,注意这里是概率性问题,下面我们测试一下:
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: { }" + Thread.currentThread().getPriority());
});
t.setPriority(3);
Thread t1 = new Thread(() -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: { }" + Thread.currentThread().getPriority());
});
t1.setPriority(7);
Thread t2 = new Thread(() -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: { }" + Thread.currentThread().getPriority());
});
t2.setPriority(10);
t.start();
t1.start();
t2.start();
}
第一次输出:
hello 7
default level: { }7
hello 10
default level: { }10
hello 3
default level: { }3
第二次:
hello 3
default level: { }3
hello 7
default level: { }7
hello 10
default level: { }10第三次
hello 10
default level: { }10
hello 7
default level: { }7
hello 3
default level: { }3
...
发现,不断的尝试之后,高级别出现的概率会比较靠前一点, 所以想要借助它来完成一些特定业务的同学注意了,不建议使用,不靠谱,之前也讲到,底层还是由操作系统调度完成
Java提供一个「线程调度器」来监视和控制处于「RUNNABLE状态」的线程。线程的调度策略采用「抢占式」,优先级高的线程比优先级低的线程会有更大的几率优先执行。在优先级相同的情况下,按照“先到先得”的原则。每个Java程序都有一个默认的主线程,就是通过JVM启动的第一个线程main线程。
除了主线程之外,b2b信息网还有一个线程是守护线程,它的优先级比较低。如果所有的非守护线程都结束了,这个守护线程也会自动结束。可以借助它实现一些特定场景,比如手动关闭线程的场景,某些场景下不关闭,会造成资源浪费,手动关闭又很麻烦。这里我们可以通过setDaemon(true)指定。
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: { }" + Thread.currentThread().getPriority());
});
t.setDaemon(true); // 默认为false
t.setPriority(10);
Thread t1 = new Thread(() -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: { }" + Thread.currentThread().getPriority());
});
t1.setPriority(7);
t.start();
t1.start();
}输出:
hello 7
default level: { }7
hello 10
default level: { }10发现即使指定了高级别,执行的优先级仍然是最低的
线程组下的优先级刚刚我们都是在main线程组下,举一反三,线程组下的优先级又是怎么样的呢❓下面,测试一下:
public static void main(String[] args) {
// 指定 name 为 g1的线程组
ThreadGroup group = new ThreadGroup("g1");
group.setMaxPriority(4);
Thread t = new Thread(group, () -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: { }" + Thread.currentThread().getPriority());
}, "t0");
t.setPriority(10);
t.start();
}输出:
hello 4
default level: { }4发现,在g1线程组下指定了最大优先级后,线程t0的优先级最大级别只能是4, 所以这也是使用线程组的好处。
我们可以通过如下方式复制线程组, ThreadGroup提供了enumerate方法:
public static void main(String[] args) throws InterruptedException {
// 指定 name 为 g1的服务器租用线程组
ThreadGroup group = new ThreadGroup("g1");
group.setMaxPriority(4);
Thread t = new Thread(group, () -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: { }" + Thread.currentThread().getPriority());
}, "t0");
t.setPriority(10);
t.start();
// 复制线程组
System.out.println(group.activeCount()); // 1
Thread[] list = new Thread[group.activeCount()];
group.enumerate(list);
Thread.sleep(3000);
System.out.println(list[0].getName()); // 输出 t0
}统一异常捕获public static void main(String[] args) {
// 指定 name 为 g1的线程组
ThreadGroup group = new ThreadGroup("g1") {
// 统一异常捕获
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName() + ": " + e.getMessage()); // t0: 我出错了
}
};
group.setMaxPriority(4);
Thread t = new Thread(group, () -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: { }" + Thread.currentThread().getPriority());
throw new RuntimeException("我出错了");
}, "t0");
t.setPriority(10);
t.start();
}向下引用的树状数据结构线程组的内部其实不单单可以放线程,其实也可以放其它线程组,我们看下源码定义
public static void main(String[] args) {
// 指定 name 为 g1的线程组
ThreadGroup group = new ThreadGroup("g1") {
// 统一异常捕获
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName() + ": " + e.getMessage()); // t0: 我出错了
}
};
group.setMaxPriority(4);
Thread t = new Thread(group, () -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: { }" + Thread.currentThread().getPriority());
throw new RuntimeException("我出错了");
}, "t0");
t.setPriority(10);
t.start();
}这里大家可以大胆去猜测一下,为什么要采用这种数据结构❓其实你通过源码发现,它的内部很多地方都调用了checkAccess方法,特别是在set操作,字面意思是检查是否有权限,我看下这个方法。
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}它调用了一个SecurityManager, 它是Java的安全管理器,它允许应用程序在执行一个可能不安全或敏感的操作前确定该操作是什么,以及是否是在允许执行该操作的安全上下文中执行它。应用程序可以允许或不允许该操作。总的来说就是保证安全性。
通过上面的了解,我们应该知道为什么要用这种树状结构了。它都是一层一层级别的控制,这么做方便去管理,提高安全性,出了问题也能很快的定位到。就像公司的人员组织架构一样,一切都是为了管理好公司。
结束语本篇内容到这里就结束了, 大家自己一定要多去理解,不要去背,。
很赞哦!(4)
相关文章
- 只要我们做的是从目前的市场情况选择域名,从简单易记,从个性特征上,我们就可以找到一个好域名进行注册。域名注册进行域名记录和解析以及绑定网站后,客户可以通过URL登录您的网站。
- TIOBE 10 月榜单:Python 夺冠,Java 和 C 长期霸权结束
- 我用这十八个神奇的库,美化了我的项目,真是亮瞎我的眼!
- 让Hi3861驱动交流电机变频器
- 域后缀首选.com,.net,然后是.cn。后缀选择不当,导致流量损失。域名是企业与互联网网址之间的链接,关键是企业在网络上存在的标志。因此,选择好域名是开展网上工作的首要重要条件。
- CIO/CTO选型数据中台的八个建议
- 说下希尔排序的过程? 希尔排序的时间复杂度和空间复杂度又是多少?
- 建议收藏!C++ Set用法大全
- 互联网中的地址是数字的IP地址,域名解析的作用主要就是为了便于记忆。
- 一日一技:Pandas 如何对列排序?
热门文章
站长推荐
2、根据用户基础选择访问提供程序。由于互联问题的存在,接入商的选择也非常重要,如果用户群主要在联通,尽量选择联通接入较好的接入商,如果用户群主要在电信,那么选择电信接入较好的接入商。如果用户组位于国家/地区,则选择更好的访问提供程序进行交互。
Python 3.10的几个好用的新特性
Go 切片导致内存泄露,被坑两次了!
使用 Grpcurl 通过命令行访问 gRPC 服务
3、商标域名一经注册,就可以作为域名裁决过程中的主要信息之一。这可以大大增加公司被抢注的相关域名胜诉的机会。
Vue 项目打包部署总结
图灵奖得主Barbara Liskov:为什么编程仍然很重要
OHOS3.0标准系统编写C程序控制LED