Java多線程16:線程組


線程組

可以把線程歸屬到某一個線程組中,線程組中可以有線程對象,也可以有線程組,組中還可以有線程,這樣的組織結構有點類似於樹的形式,如圖所示:

線程組的作用是:可以批量管理線程或線程組對象,有效地對線程或線程組對象進行組織

 

線程關聯線程組:1級關聯

所謂1級關聯就是父對象中有子對象,但並不創建孫對象。這種情況在開發中很常見,比如創建一些線程時,為了有效對這些線程進行阻止管理,通常情況下是創建一個線程組,然后再將部分線程歸屬到該組中,以此來對零散的線程對象進行有效的管理。

看一下簡單的1級關聯的例子:

public class MyThread49 implements Runnable
{
    public void run()
    {
        try
        {
            while (!Thread.currentThread().isInterrupted())
            {
                System.out.println("ThreadName = " + Thread.currentThread().getName());
                Thread.sleep(3000);
            }
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}
public static void main(String[] args)
{
    MyThread49 mt0 = new MyThread49();
    MyThread49 mt1 = new MyThread49();
    ThreadGroup tg = new ThreadGroup("新建線程組1");
    Thread t0 = new Thread(tg, mt0);
    Thread t1 = new Thread(tg, mt1);
    t0.start();
    t1.start();
    System.out.println("活動的線程數為:" + tg.activeCount());
    System.out.println("線程組的名稱為:" + tg.getName());
}

看一下運行結果:

活動的線程數為:2
ThreadName = Thread-1
ThreadName = Thread-0
線程組的名稱為:新建線程組1
ThreadName = Thread-1
ThreadName = Thread-0
ThreadName = Thread-1
ThreadName = Thread-0
ThreadName = Thread-1
ThreadName = Thread-0
...

控制台上打印出的信息表示線程組中有兩個線程,並且打印出了線程組的名稱。另外,兩個線程無限隔3秒打印,也符合代碼預期

 

線程關聯線程組:多級關聯

所謂的多級關聯就是父對象中有子對象,子對象中再創建子對象買也就出現了子孫的效果了。但是這種寫法在開發中不太常見,因為線程樹如果涉及得復雜反而不利於線程對象的管理,不過JDK確實提供了多級關聯的線程樹結構。

多級關聯的代碼就不寫了,簡單看一下怎么使用關機關聯,查看下JDK API的ThreadGroup構造方法:

注意一下第二個,假如要使用多級關聯一般就是用第二個構造函數。第一個參數表示新線程組的父線程組,第二個參數表示新線程組的名稱,有了父線程組和新線程組的名稱,自然可以構造出一個新的線程組來了。

當然用第一個構造方法也是可以的,下一部分就會提到。

另外注意一點,線程必須啟動后才能歸到指定線程組中

 

線程組自動歸屬特性

自動歸屬的意思就是自動歸到當前線程組中,看一下例子:

public static void main(String[] args)
{
    System.out.println("A處線程:" + Thread.currentThread().getName() + ", 所屬線程:" + Thread.currentThread().getThreadGroup().getName() + 
        ", 組中有線程組數量:" + Thread.currentThread().getThreadGroup().activeGroupCount());
    ThreadGroup group = new ThreadGroup("新的組");
    System.out.println("B處線程:" + Thread.currentThread().getName() + ", 所屬線程:" + Thread.currentThread().getThreadGroup().getName() + 
        ", 組中有線程組數量:" + Thread.currentThread().getThreadGroup().activeGroupCount());
    ThreadGroup[] tg = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
    Thread.currentThread().getThreadGroup().enumerate(tg);
    for (int i = 0; i < tg.length; i++)
        System.out.println("第一個線程組名稱為:" + tg[i].getName());
}

看一下運行結果:

A處線程:main, 所屬線程:main, 組中有線程組數量:0
B處線程:main, 所屬線程:main, 組中有線程組數量:1
第一個線程組名稱為:新的組

從結果看,實例化了一個group出來,沒有指定線程組,那么自動歸到當前線程所屬的線程組中,也就是隱式地在一個線程組中添加了一個子線程組。

 

根線程組

看一下根線程組: 

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

看一下運行結果:

system
Exception in thread "main" java.lang.NullPointerException
    at com.xrq.example.e49.TestMain49.main(TestMain49.java:11)

運行結果可以得出兩個結論:

1、根線程組就是系統線程組system

2、拋空指針異常是因為系統線程組上已經沒有線程組了,所以system的getParent()方法返回的是null,對null調用getName()方法自然是NullPointerException

關於根線程組,看一下ThreadGroup的源碼:

/**
 * Creates an empty Thread group that is not in any Thread group. 
 * This method is used to create the system Thread group.
 */
private ThreadGroup() {    // called from C code
this.name = "system";
this.maxPriority = Thread.MAX_PRIORITY;
}

一個私有構造方法,說明不是對開發者開放的。注釋上已經寫得很清楚了,這是C代碼調用的,用於構建系統線程組。

 

批量停止組內線程

使用線程組自然是要對線程做批量管理的,到目前為止我們似乎都沒有看見如何對線程組內的線程做批量操作,最后來看一下批量操作線程組內的線程:

public class MyThread50 extends Thread
{
    public MyThread50(ThreadGroup tg, String name)
    {
        super(tg, name);
    }
    
    public void run()
    {
        System.out.println("ThreadName = " + Thread.currentThread().getName() + 
                "准備開始死循環了");
        while (!this.isInterrupted()){}
        System.out.println("ThreadName = " + Thread.currentThread().getName() + 
                "結束了");
    }
}

開3個線程:

public static void main(String[] args) throws InterruptedException
{
    ThreadGroup tg = new ThreadGroup("我的線程組");
    MyThread50 mt = null;
    for (int i = 0; i < 3; i++)
    {
        mt = new MyThread50(tg, "線程" + i);
        mt.start();
    }
    Thread.sleep(5000);
    tg.interrupt();
    System.out.println("調用了interrupt()方法");
}

看一下運行結果:

ThreadName = 線程0准備開始死循環了
ThreadName = 線程2准備開始死循環了
ThreadName = 線程1准備開始死循環了
調用了interrupt()方法
ThreadName = 線程2結束了
ThreadName = 線程1結束了
ThreadName = 線程0結束了

看到調用了ThreadGroup中的interrupt()方法批量中斷了線程組內的線程,這就是ThreadGroup的作用。更多線程組的操作可以查看JDK API。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM