java高併發系列 - 第8天:線程組

線程組

咱們能夠把線程歸屬到某個線程組中,線程組能夠包含多個線程以及線程組,線程和線程組組成了父子關係,是個樹形結構,以下圖:java

使用線程組能夠方便管理線程,線程組提供了一些方法方便方便咱們管理線程。api

建立線程關聯線程組

建立線程的時候,能夠給線程指定一個線程組,代碼以下:微信

package com.itsoku.chat02;

import java.util.concurrent.TimeUnit;

/**
 * <b>description</b>: <br>
 * <b>time</b>:2019/7/13 17:53 <br>
 * <b>author</b>:微信公衆號:路人甲Java,專一於java技術分享(帶你玩轉 爬蟲、分佈式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注!
 */
public class Demo1 {
    public static class R1 implements Runnable {
        @Override
        public void run() {
            System.out.println("threadName:" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadGroup threadGroup = new ThreadGroup("thread-group-1");
        Thread t1 = new Thread(threadGroup, new R1(), "t1");
        Thread t2 = new Thread(threadGroup, new R1(), "t2");
        t1.start();
        t2.start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println("活動線程數:" + threadGroup.activeCount());
        System.out.println("活動線程組:" + threadGroup.activeGroupCount());
        System.out.println("線程組名稱:" + threadGroup.getName());
    }
}

輸出結果:併發

threadName:t1
threadName:t2
活動線程數:2
活動線程組:0
線程組名稱:thread-group-1

activeCount()方法能夠返回線程組中的全部活動線程數,包含下面的全部子孫節點的線程,因爲線程組中的線程是動態變化的,這個值只能是一個估算值。異步

爲線程組指定父線程組

建立線程組的時候,能夠給其指定一個父線程組,也能夠不指定,若是不指定父線程組,則父線程組爲當前線程的線程組,java api有2個經常使用的構造方法用來建立線程組:分佈式

public ThreadGroup(String name)
public ThreadGroup(ThreadGroup parent, String name)

第一個構造方法未指定父線程組,看一下內部的實現:ide

public ThreadGroup(String name) {
        this(Thread.currentThread().getThreadGroup(), name);
    }

系統自動獲取當前線程的線程組做爲默認父線程組。高併發

上一段示例代碼:大數據

package com.itsoku.chat02;

import java.util.concurrent.TimeUnit;

/**
 * <b>description</b>: <br>
 * <b>time</b>:2019/7/13 17:53 <br>
 * <b>author</b>:微信公衆號:路人甲Java,專一於java技術分享(帶你玩轉 爬蟲、分佈式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注!
 */
public class Demo2 {
    public static class R1 implements Runnable {
        @Override
        public void run() {
            Thread thread = Thread.currentThread();
            System.out.println("所屬線程組:" + thread.getThreadGroup().getName() + ",線程名稱:" + thread.getName());
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadGroup threadGroup1 = new ThreadGroup("thread-group-1");
        Thread t1 = new Thread(threadGroup1, new R1(), "t1");
        Thread t2 = new Thread(threadGroup1, new R1(), "t2");
        t1.start();
        t2.start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println("threadGroup1活動線程數:" + threadGroup1.activeCount());
        System.out.println("threadGroup1活動線程組:" + threadGroup1.activeGroupCount());
        System.out.println("threadGroup1線程組名稱:" + threadGroup1.getName());
        System.out.println("threadGroup1父線程組名稱:" + threadGroup1.getParent().getName());
        System.out.println("----------------------");
        ThreadGroup threadGroup2 = new ThreadGroup(threadGroup1, "thread-group-2");
        Thread t3 = new Thread(threadGroup2, new R1(), "t3");
        Thread t4 = new Thread(threadGroup2, new R1(), "t4");
        t3.start();
        t4.start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println("threadGroup2活動線程數:" + threadGroup2.activeCount());
        System.out.println("threadGroup2活動線程組:" + threadGroup2.activeGroupCount());
        System.out.println("threadGroup2線程組名稱:" + threadGroup2.getName());
        System.out.println("threadGroup2父線程組名稱:" + threadGroup2.getParent().getName());

        System.out.println("----------------------");
        System.out.println("threadGroup1活動線程數:" + threadGroup1.activeCount());
        System.out.println("threadGroup1活動線程組:" + threadGroup1.activeGroupCount());

        System.out.println("----------------------");
        threadGroup1.list();
    }
}

輸出結果:this

所屬線程組:thread-group-1,線程名稱:t1
所屬線程組:thread-group-1,線程名稱:t2
threadGroup1活動線程數:2
threadGroup1活動線程組:0
threadGroup1線程組名稱:thread-group-1
threadGroup1父線程組名稱:main
----------------------
所屬線程組:thread-group-2,線程名稱:t4
所屬線程組:thread-group-2,線程名稱:t3
threadGroup2活動線程數:2
threadGroup2活動線程組:0
threadGroup2線程組名稱:thread-group-2
threadGroup2父線程組名稱:thread-group-1
----------------------
threadGroup1活動線程數:4
threadGroup1活動線程組:1
----------------------
java.lang.ThreadGroup[name=thread-group-1,maxpri=10]
    Thread[t1,5,thread-group-1]
    Thread[t2,5,thread-group-1]
    java.lang.ThreadGroup[name=thread-group-2,maxpri=10]
        Thread[t3,5,thread-group-2]
        Thread[t4,5,thread-group-2]

代碼解釋:

  1. threadGroup1未指定父線程組,系統獲取了主線程的線程組做爲threadGroup1的父線程組,輸出結果中是:main
  2. threadGroup1爲threadGroup2的父線程組
  3. threadGroup1活動線程數爲4,包含了threadGroup1線程組中的t一、t2,以及子線程組threadGroup2中的t三、t4
  4. 線程組的list()方法,將線程組中的全部子孫節點信息輸出到控制檯,用於調試使用

根線程組

獲取根線程組

package com.itsoku.chat02;

/**
 * <b>description</b>: <br>
 * <b>time</b>:2019/7/13 17:53 <br>
 * <b>author</b>:微信公衆號:路人甲Java,專一於java技術分享(帶你玩轉 爬蟲、分佈式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注!
 */
public class Demo3 {

    public static void main(String[] args) {
        System.out.println(Thread.currentThread());
        System.out.println(Thread.currentThread().getThreadGroup());
        System.out.println(Thread.currentThread().getThreadGroup().getParent());
        System.out.println(Thread.currentThread().getThreadGroup().getParent().getParent());
    }
}

運行上面代碼,輸出:

Thread[main,5,main]
java.lang.ThreadGroup[name=main,maxpri=10]
java.lang.ThreadGroup[name=system,maxpri=10]
null

從上面代碼能夠看出:

  1. 主線程的線程組爲main
  2. 根線程組爲system

看一下ThreadGroup的源碼:

private ThreadGroup() {     // called from C code
        this.name = "system";
        this.maxPriority = Thread.MAX_PRIORITY;
        this.parent = null;
    }

發現ThreadGroup默認構造方法是private的,是由c調用的,建立的正是system線程組。

批量中止線程

調用線程組interrupt(),會將線程組樹下的全部子孫線程中斷標誌置爲true,能夠用來批量中斷線程。

示例代碼:

package com.itsoku.chat02;

import java.util.concurrent.TimeUnit;

/**
 * <b>description</b>: <br>
 * <b>time</b>:2019/7/13 17:53 <br>
 * <b>author</b>:微信公衆號:路人甲Java,專一於java技術分享(帶你玩轉 爬蟲、分佈式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注!
 */
public class Demo4 {
    public static class R1 implements Runnable {
        @Override
        public void run() {
            Thread thread = Thread.currentThread();
            System.out.println("所屬線程組:" + thread.getThreadGroup().getName() + ",線程名稱:" + thread.getName());
            while (!thread.isInterrupted()) {
                ;
            }
            System.out.println("線程:" + thread.getName() + "中止了!");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadGroup threadGroup1 = new ThreadGroup("thread-group-1");
        Thread t1 = new Thread(threadGroup1, new R1(), "t1");
        Thread t2 = new Thread(threadGroup1, new R1(), "t2");
        t1.start();
        t2.start();

        ThreadGroup threadGroup2 = new ThreadGroup(threadGroup1, "thread-group-2");
        Thread t3 = new Thread(threadGroup2, new R1(), "t3");
        Thread t4 = new Thread(threadGroup2, new R1(), "t4");
        t3.start();
        t4.start();
        TimeUnit.SECONDS.sleep(1);

        System.out.println("-----------threadGroup1信息-----------");
        threadGroup1.list();

        System.out.println("----------------------");
        System.out.println("中止線程組:" + threadGroup1.getName() + "中的全部子孫線程");
        threadGroup1.interrupt();
        TimeUnit.SECONDS.sleep(2);

        System.out.println("----------threadGroup1中止後,輸出信息------------");
        threadGroup1.list();
    }
}

輸出:

所屬線程組:thread-group-1,線程名稱:t1
所屬線程組:thread-group-1,線程名稱:t2
所屬線程組:thread-group-2,線程名稱:t3
所屬線程組:thread-group-2,線程名稱:t4
-----------threadGroup1信息-----------
java.lang.ThreadGroup[name=thread-group-1,maxpri=10]
    Thread[t1,5,thread-group-1]
    Thread[t2,5,thread-group-1]
    java.lang.ThreadGroup[name=thread-group-2,maxpri=10]
        Thread[t3,5,thread-group-2]
        Thread[t4,5,thread-group-2]
----------------------
中止線程組:thread-group-1中的全部子孫線程
線程:t4中止了!
線程:t2中止了!
線程:t1中止了!
線程:t3中止了!
----------threadGroup1中止後,輸出信息------------
java.lang.ThreadGroup[name=thread-group-1,maxpri=10]
    java.lang.ThreadGroup[name=thread-group-2,maxpri=10]

中止線程以後,經過list()方法能夠看出輸出的信息中不包含已結束的線程了。

多說幾句,建議你們再建立線程或者線程組的時候,給他們取一個有意義的名字,對於計算機來講,可能名字並不重要,可是在系統出問題的時候,你可能會去查看線程堆棧信息,若是你看到的都是t一、t二、t3,估計本身也比較崩潰,若是看到的是httpAccpHandler、dubboHandler相似的名字,應該會好不少。

java高併發系列交流羣

相關文章
相關標籤/搜索