線程管理

1.線程組

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

​ Thread類有幾個構造方法容許在建立線程時指定線程組,若是在建立線程時沒有指定線程組,則該線程就屬於父線程所在的線程組,JVM在建立main線程時會爲它指定一個線程組,所以每一個java線程都有一個線程組與之相關,能夠調用getThreadGroup()返回線程組嗎。sql

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()返回當前線程組及子線程組中活動線程的數量ide

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

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

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

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

getParent()返回父線程組code

getName()返回線程組的名字blog

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

相關文章
相關標籤/搜索