一、线程局部变量
在线程中使用共享变量肯定是存在风险。为了规避这个风险,利用同步机制,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