java中默认启动就有2个线程组:
线程组之间是嵌套的关系,system线程组就嵌套了main线程组.
我们如果没有给线程指定线程组,则默认是创建在main线程组中的.同理线程池如果没有指定线程组,也是归属在main线程组中的.cuiyaonan2000@163.com
线程运行中途不能改变它所属的线程组,也就是说线程一旦指定所在的线程组,就直到该线程结束。
执行如下代码
- package nan.yao.cui.test;
-
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ThreadPoolExecutor;
-
- /**
- * @Author: cuiyaonan2000@163.com
- * @Description: todo
- * @Date: Created at 2022-6-6 9:38
- */
- public class Test01 implements Runnable{
-
- public static void main(String[] args){
-
- //连接池的代码
- ExecutorService newFixThreadPool_1 = Executors.newCachedThreadPool();
- newFixThreadPool_1.submit(new Test01());
-
-
- // System.out.println("自定义的线程组");
- // ThreadGroup tg = new ThreadGroup();
- //
- // new Thread();
- // System.out.println();
- //
- // System.out.println(tg.getParent().getName());
-
-
-
- }
-
- public void showThreadGroup(Thread thread){
-
- ThreadGroup threadGroup = thread.getThreadGroup();
-
- do{
- System.out.println("线程组的名字是:" + threadGroup.getName() +" 当前的优先级是:" + threadGroup.getMaxPriority());
- System.out.println("是否是守护线程组:" + threadGroup.isDaemon() +" 当前线程组的线程数是:" + threadGroup.activeCount());
- threadGroup = threadGroup.getParent();
- }while(threadGroup != null );
- }
-
- @Override
- public void run() {
- ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
-
- do{
- System.out.println("线程组的名字是:" + threadGroup.getName() +" 当前的优先级是:" + threadGroup.getMaxPriority());
- System.out.println("是否是守护线程组:" + threadGroup.isDaemon() +" 当前线程组的线程数是:" + threadGroup.activeCount());
- threadGroup = threadGroup.getParent();
- }while(threadGroup != null );
- }
- }
我们创建的线程必然是要有线程组的,(注意是一定会有线程组cuiyaonan2000@163.com).
线程组顾名思义就是用于批量管理线程,省去我们为每一个线程设置优先级,异常处理等信息.
线程池是用于管理线程的生命周期的,从创建,就绪,运行,等待,死亡,超时.另线程池里的线程创建默认也是制定了线程组的,即只要是线程一定会有个线程组.
为什么我们创建的线程一定会设置线程组的原因?
针对我们创建的线程,以new Thread 为例
如上Thread的构造方法中,如果要设置ThreadGroup则一定不能为空.
这里我们看下没有传递ThreadGroup的构造函数.以public Thread() 为例子
可以看到内部又调用了init()且传递的ThreadGroup为null
init() 内容如下
- /**
- * Initializes a Thread.
- *
- * @param g the Thread group
- * @param target the object whose run() method gets called
- * @param name the name of the new Thread
- * @param stackSize the desired stack size for the new thread, or
- * zero to indicate that this parameter is to be ignored.
- * @param acc the AccessControlContext to inherit, or
- * AccessController.getContext() if null
- * @param inheritThreadLocals if {@code true}, inherit initial values for
- * inheritable thread-locals from the constructing thread
- */
- private void init(ThreadGroup g, Runnable target, String name,
- long stackSize, AccessControlContext acc,
- boolean inheritThreadLocals) {
- if (name == null) {
- throw new NullPointerException("name cannot be null");
- }
-
- this.name = name;
-
- Thread parent = currentThread();
- SecurityManager security = System.getSecurityManager();
- if (g == null) {
- /* Determine if it's an applet or not */
-
- /* If there is a security manager, ask the security manager
- what to do. */
- if (security != null) {
- g = security.getThreadGroup();
- }
-
- /* If the security doesn't have a strong opinion of the matter
- use the parent thread group. */
- if (g == null) {
- g = parent.getThreadGroup();
- }
- }
-
- /* checkAccess regardless of whether or not threadgroup is
- explicitly passed in. */
- g.checkAccess();
-
- /*
- * Do we have the required permissions?
- */
- if (security != null) {
- if (isCCLOverridden(getClass())) {
- security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
- }
- }
-
- g.addUnstarted();
-
- this.group = g;
- this.daemon = parent.isDaemon();
- this.priority = parent.getPriority();
- if (security == null || isCCLOverridden(parent.getClass()))
- this.contextClassLoader = parent.getContextClassLoader();
- else
- this.contextClassLoader = parent.contextClassLoader;
- this.inheritedAccessControlContext =
- acc != null ? acc : AccessController.getContext();
- this.target = target;
- setPriority(priority);
- if (inheritThreadLocals && parent.inheritableThreadLocals != null)
- this.inheritableThreadLocals =
- ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
- /* Stash the specified stack size in case the VM cares */
- this.stackSize = stackSize;
-
- /* Set thread ID */
- tid = nextThreadID();
- }
如下如果我们没有指定new Thread()的线程组,则默认会使用创建该子线程的线程组,如下图所示(一般为main()线程组)
如上我们可以在创建Thread中设置线程组.那自定义线程组的构造函数如下所示
这里主要看下只需要name的构造函数
由此可见我们创建的线程组一定是 main线程组的子线程组.
以代码如下代码为例:
- //连接池的代码
- ExecutorService newFixThreadPool_1 = Executors.newCachedThreadPool();
- newFixThreadPool_1.submit(new Test01());
线程池的创建主要是如下的代码产生
在如下所示,线程池创建的线程所属的线程组是创建线程的线程组
这个很容易理解,就是为线程组的线程设置默认的属性和处理方法.(因为是默认的属性和方法,自定线程当然可以进行覆盖)
这里距离几种重要的属性和默认方法的设置
优先级由1到10之间的整数表示。
优先级为1的线程优先级最低。优先级为10的线程具有最高优先级。
在Thread类中定义了三个常量来表示下表中列出的三个不同的线程优先级。
线程优先级常量 | 整数值 |
---|---|
MIN_PRIORITY | 1 |
NORM_PRIORITY | 5 |
MAX_PRIORITY | 10 |
线程的异常处理有4个level
优先级必然是:线程对象设置>线程组对象设置>线程类静态方法设置
- package nan.yao.cui.test;
-
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ThreadPoolExecutor;
-
- /**
- * @Author: cuiyaonan2000@163.com
- * @Description: todo
- * @Date: Created at 2022-6-6 9:38
- */
- public class Test01 implements Runnable {
-
- public static void main(String[] args) throws InterruptedException {
-
- //针对线程类的静态方法
- Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
- System.out.println("this is setDefaultUncaughtExceptionHandler .the thread" + t.getName() + " catch the exception:" + e.getMessage());
- });
-
-
- //相当于是集成了ThreadGroup并且重写了uncaughtException 方法
- ThreadGroup tg = new ThreadGroup("myTG"){
- @Override
- public void uncaughtException(Thread t, Throwable e) {
- System.out.println( "线程组:" + getName() + "下的线程:"+ t.getName() + "出现了异常:" + e.getMessage());
- }
- };
- //设置线程组的权限
- tg.setMaxPriority(Thread.MAX_PRIORITY);
-
-
- Test01 test01 = new Test01();
- Test01 test02 = new Test01();
- Test01 test03 = new Test01();
- Test01 test04 = new Test01();
-
-
- Thread t1 = new Thread(tg,test01,"第一个异常");
- Thread t2 = new Thread(test01,"第二个异常");
-
-
- //针对该线程的异常捕获
- t2.setUncaughtExceptionHandler((t, e) -> {
- System.out.println("this is setUncaughtExceptionHandler .the thread" + t.getName() +" catch the exception:" + e.getMessage());
- });
-
- //会使用默认的异常捕获
- Thread t3 = new Thread(test03,"第三个异常");
-
- Thread t4 = new Thread(tg,test04,"第四个异常");
- t4.setUncaughtExceptionHandler((t, e) -> {
- System.out.println("this is setUncaughtExceptionHandler .the thread" + t.getName() +" catch the exception:" + e.getMessage());
- });
-
-
- t1.start();
- t2.start();
- t3.start();
- t4.start();
-
-
- Thread.sleep(5000);
- }
-
-
- @Override
- public void run() {
- throw new RuntimeException("this is business exception ,throwed by " + Thread.currentThread().getName());
- }
- }