多線程之線程管理


1.線程組

​ 類似於計算機中,使用文件夾管理文件,也可以使用線程組來管理線程,在線程組中定義一組相似的線程,在在線程組中也可以定義子線程組。

​ Thread類有幾個構造方法允許在創建線程時指定線程組,如果在創建線程時沒有指定線程組,則該線程就屬於父線程所在的線程組,JVM在創建main線程時會為它指定一個線程組,因此每個java線程都有一個線程組與之相關,可以調用getThreadGroup()返回線程組嗎。

1.1返回當前main的線程組

public class ThreadGroupText {
    public static void main(String[] args) {
        ThreadGroup threadGroup=Thread.currentThread().getThreadGroup();
        System.out.println(threadGroup);
    }
}

image-20210330224221571

1.2 定義線程組,如果不指定線程組,則自動歸為當前所屬的線程

public class ThreadGroupText {
    public static void main(String[] args) {
       ThreadGroup threadGroup1=new ThreadGroup("group1");
        System.out.println(threadGroup1);
    }
}

image-20210330225034049

1.3 定義線程組同時指定父線程

public class ThreadGroupText {
    public static void main(String[] args) {
        ThreadGroup threadGroup=Thread.currentThread().getThreadGroup();
        System.out.println(threadGroup);
        
         ThreadGroup threadGroup1=new ThreadGroup("group1");
        System.out.println(threadGroup1.getParent());
        
        ThreadGroup threadGroup2=new ThreadGroup(threadGroup,"group2");
        System.out.println("threadGroup1-->"+threadGroup1.getParent());
        System.out.println("threadGroup2-->"+threadGroup2.getParent());
    }
}

image-20210330225150689

1.4創建線程時指定所屬線程組

public class ThreadGroupText {
    public static void main(String[] args) {
        Runnable r=new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread());
            }
        };
        Thread t1=new Thread(r,"t1");
        System.out.println(t1);
    }
}
Thread[t1,5,main]//線程名稱 優先級 父線程組

在main線程中創建了t1線程,main為父線程,t1為子線程,t1沒有指定線程組t1就屬於父線程組。

1.5線程組的基本操作

activecount()返回當前線程組及子線程組中活動線程的數量

activeGroupCount()返回當前線程組以及子線程組中活動線程組的數量

int enumerate(Thread[] list)將當前線程組中的活動線程復制到參數數組中

enmerate(ThreadGroup[] list) 將當前線程組中的活動線程復制到參數數組中

getMaxPriority()獲取線程組最大優先級,默認是10

getParent()返回父線程組

getName()返回線程組的名字

interrup()中斷線程組的所有線程

IsDaemon()判斷當前線程組是否為守護線程

list()將當前線程組中的活動線程打印出來

ParentOf(HtreadGroup g)判斷當前線程組是否為參數線程組的父線程組

setDaemon()設置線程組為守護線程

2.捕獲線程的執行異常

​ 在線程Run方法中,如果有受檢異常必須捕獲處理,如果想要獲得Run方法中出現的運行時異常,可以通過回調UncaughtExceptHandler接口獲得哪個線程出現了運行時異常。

2.1.Thread類相關異常處理方法

getdefaultUncaughtExceptHandle獲得全局的UncaughtExceptHandler

getUncaughtExceptHandler獲得當前線程的UncaughtExceptHandler

setdefaultUncaughtExceptHandle設置全局的UncaughtExceptHandler

setUncaughtExceptHandler設置當前線程的UncaughtExceptHandler

當線程出現異常,JVM會調用Thread類的dispatchcaughtExceptHandler(Throwable e)方法,該方法會調用

getUncaughtExceptHandler().UncaughtException(this e),如果想要獲得異常信息,就需要設置線程的UncaughtExceptHandler

2.2設置線程異常的回調接口方法

package com;

public class ThreadExcept{
    public static void main(String[] args) {
        //設置線程全局回調接口
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                //t參數接受發生異常的線程,e就是該線程中的異常信息
                System.out.println(t.getName()+"發生了"+e.getMessage());
            }
        });

        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
           String name=null;
                System.out.println(name.length());
            }
        });
        t1.start();
    }
}

image-20210403152038162

​ 在實際開發中,這種設計異常處理方式還是比較常用的,尤其是異常執行方法

​ 如果線程產生異常,JVM會調用dispatchcaughtException方法,該方法中調用了getUncaughtExceptionHandler().UncaughtException(this e);如果當前線程設置了UncaughtExceptionHandler回調接口就直接調用它自己的UncaughtException方法,如果沒有設置則調用當前線程所在線程組UncaughtExceptionHandler回調接口UncaughtException方法,如果線程組也沒有設置回調接口,則直接把異常的棧信息定向Sysytem.err中。

3.注入Hook鈎子線程

​ 很多軟件包括Mysql、Zookeeper、Kafka都存在Hook線程的效驗機制,目的就是效驗進程是否已啟動,防止反復啟動應用程序。

​ Hook線程也叫鈎子線程,當JVM退出的時候會執行Hook線程,經常在程序啟動的時候創建一個.lock線程,用.lock校驗程序是否在啟動,在程序退出時刪除.lock文件,在Hook線程中處理防止重復啟動之外還可以做資源釋放,盡量避免在Hook線程中做復雜操作。

package com;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class HookText {
    public static void main(String[] args) throws IOException, InterruptedException {
        //注入Hook線程,在程序退出時,刪除.lock文件
        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run() {
                System.out.println("JVM退出,會啟動當前Hook線程,在Hook線程中刪除.lock文件");
                getFile().toFile().delete();
            }
        });

        //檢查lock文件是否存在
        if(getFile().toFile().exists())
        {
            throw  new RuntimeException("程序已啟動");
        }
        else
        {
            getFile().toFile().createNewFile();
            System.out.println("創建lock文件");
        }

        for (int i = 0; i < 100; i++) {
            System.out.println("程序正在運行");
            Thread.sleep(100);
        }
    }

    private  static Path getFile()
    {
        return Paths.get("","tmp.lock");
    }
}

當項目已啟動,JVM會在項目文件夾目錄會自動創建一個.lock文件

image-20210403154703343

只有當項目自動運行結束JVM自動退出時會刪除.lock文件,當讓程序運行時停止,.lock文件不會被刪除,再運行會拋出異常

image-20210403155048752


免責聲明!

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



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