JAVA基礎23-多執行緒(二)【執行緒區域性變數和未捕獲異常處理器】
一、執行緒區域性變數
線上程中使用共享變數肯定是存在風險。為了規避這個風險,利用同步機制,volatile這些方法都可以。但是也可為每個執行緒分配一個變數。使用ThreadLocal輔助類為各個執行緒提供各自的例項。
ThreadLocal為每個使用該變數的執行緒分配一個獨立的變數副本,每一個執行緒都可以獨立地改變自己的副本,而不影響其他執行緒。
2 ThreadLocal方法及使用示例
ThreadLocal<T>類在Spring,Hibernate等框架中起到了很大的作用。為了解釋ThreadLocal類的工作原理,必須同時介紹與其工作甚密的其他幾個類,包括內部類ThreadLocalMap,和執行緒類Thread。所有方法如下圖:
四個核心方法說明如下:
T get() 返回此執行緒區域性變數的當前執行緒副本中的值。
protected T initialValue() 返回此執行緒區域性變數的當前執行緒的“初始值”。
void remove() 移除此執行緒區域性變數當前執行緒的值。
void set(T value) 將此執行緒區域性變數的當前執行緒副本中的值設定為指定值。
package com.demo9aa.demo8;
import java.util.Scanner;
public class Bank extends Thread {
ThreadLocal<Integer> b=new ThreadLocal<>();
@Override
public void run() {
Scanner s=new Scanner(System.in);
System.out.println(Thread.currentThread().getName());
int i=s.nextInt();
b.set(i);
s.close();
System.out.println(b.get());
// TODO Auto-generated method stub
super.run();
}
}
//--------------------------------------------------------------------
package com.demo9aa.demo8;
public class Bb {
public static void main(String[] args) {
Bank b=new Bank();
Bank b1=new Bank();
b.start();
b1.start();
}
}
二、未捕獲異常處理機制
A:場景再現
run方法不能丟擲任何檢查性異常,但是對於非檢查性異常,則會導致執行緒異常死亡
例子如下:
//------------------------------------執行時異常----
//主函式
package com.demo9aa.demo9.demo1;
public class Main {
public static void main(String[] args) {
Thread a=new Thread(new ThreadA());
try {
a.start();
} catch (RuntimeException e) {
// TODO: handle exception
System.out.println("12313");
}
}
}
//TheadA
package com.demo9aa.demo9.demo1;
public class ThreadA implements Runnable {
@Override
public void run() {
int[] i={1,2};
System.out.println(i[3]);
// TODO Auto-generated method stub
}
}
//執行結果
未輸出catch語句
丟擲異常,執行緒終止
B:如何捕獲run方法中的檢查性異常呢?
B-1:JVM讓提供了執行緒未捕獲異常處理機制,
通過Thread的靜態方法:setDefaultUncaughtExceptionHandler方法設定所有執行緒的預設未捕獲異常處理器
通過Thread的成員方法:setUncaughtExceptionHandler方法設定當前執行緒的未捕獲異常處理器
B-2: 預設未捕獲異常處理器、特定的未捕獲異常處理器
根據B-1可知,如何設定未捕獲處理器
其執行優先順序如下:
若特定的Thread物件,設定了未捕獲異常處理器,則處理器為:“特定的未捕獲異常處理器”
若無設定“特定的未捕獲異常處理器”,則有如下情況
設定了 “預設未捕獲異常處理器”;則處理器為該未捕獲異常處理器,
未設定"預設未捕獲異常處理器",則處理器為:該執行緒所物件的ThreadGroup類的物件。
如下兩個圖:
C:如何定義未捕獲的異常處理器
處理器必須實現 java.lang.Thread.UncaughtExceptionHandler介面。並實現 void uncaughtException(Thread t,Throwable a)方法。
//-------------------DefaultUncaughtExceptionHandler------
package com.demo9aa.demo9.demo1;
import java.lang.Thread.UncaughtExceptionHandler;
public class DefaultUncaughtExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("預設處理器:"+e.getMessage());
// TODO Auto-generated method stub
}
}
//--------------------------UncaughtExceptionHandlerA ------------------------
package com.demo9aa.demo9.demo1;
import java.lang.Thread.UncaughtExceptionHandler;
public class UncaughtExceptionHandlerA implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
// TODO Auto-generated method stub
System.out.println("特定的處理器:"+e.getMessage());
}
}
D:完整例子
//-----------------ThreadError -------------
package com.demo9aa.demo9.demo1;
public class ThreadError implements Runnable {
@Override
public void run() {
int[] i={1,2};
System.out.println(i[3]);
// TODO Auto-generated method stub
}
}
//--------------------------main-----------------
package com.demo9aa.demo9.demo1;
import java.lang.Thread.UncaughtExceptionHandler;
public class Main {
public static void main(String[] args) {
Thread a=new Thread(new ThreadError());
a.setUncaughtExceptionHandler(new UncaughtExceptionHandlerA());
a.start();
//設定了特定處理器之後
// a.setUncaughtExceptionHandler(new UncaughtExceptionHandlerA());
// System.out.println(a.getUncaughtExceptionHandler().getClass().getSimpleName());
}
}
//------------------------------輸出-------------------------
特定的處理器:java.lang.ArrayIndexOutOfBoundsException: 3