Java多线程编程核心技术---拾遗增补

线程状态验证
public class MyThread extends Thread {
	public MyThread() {
		System.out.println("构造方法中的状态:" + Thread.currentThread().getState());//RUNNABLE
	}
	@Override
	public void run() {
		System.out.println("run方法中的状态:" + Thread.currentThread().getState());//RUNNABLE
		try {
			Thread.sleep(1000);
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
	public static void main(String[] args) {
		try {
			MyThread thread = new MyThread();
			System.out.println("main方法中的状态1:" + thread.getState());//NEW
			Thread.sleep(1000);
			thread.start();
			Thread.sleep(500);
			System.out.println("main方法中的状态2:" + thread.getState());//TIMED_WAITING
			Thread.sleep(1200);
			System.out.println("main方法中的状态3:" + thread.getState());//TERMINATED
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

运行程序控制台输出结果如下:

构造方法中的状态:RUNNABLE
main方法中的状态1:NEW
run方法中的状态:RUNNABLE
main方法中的状态2:TIMED_WAITING
main方法中的状态3:TERMINATED

public class Service {
	synchronized static public void serviceMethod(){
		try {
			System.out.println(Thread.currentThread().getName() + "进入了serviceMethod方法");
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

public class MyThread1 extends Thread {
	@Override
	public void run() {
		Service.serviceMethod();
	}
}

public class MyThread2 extends Thread {
	@Override
	public void run() {
		Service.serviceMethod();
	}
}

public class Main {
	public static void main(String[] args) throws InterruptedException {
		MyThread1 t1 = new MyThread1();
		t1.start();
		MyThread1 t2 = new MyThread1();
		t2.start();
		Thread.sleep(2000);
		System.out.println("main t1 :" + t1.getState());
		System.out.println("main t2 :" + t2.getState());
	}
}

运行程序,控制台打印结果如下:

Thread-0进入了serviceMethod方法
main t1 :TIMED_WAITING
main t2 :BLOCKED
Thread-1进入了serviceMethod方法

线程对象关联线程组:1级关联

所谓的1级关联就是父对象中有子对象,但是并不创建孙对象。

public class ThreadA extends Thread {
	@Override
	public void run() {
		try {
			while (!Thread.currentThread().isInterrupted()) {
				System.out.println("ThreadName=" + ThreadA.currentThread().getName());
				Thread.sleep(3000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

public class Main {
	public static void main(String[] args) {
		ThreadA a = new ThreadA();
		ThreadB b = new ThreadB();
		ThreadGroup group = new ThreadGroup("My-Thread-Group");
		Thread aThread = new Thread(group, a);
		Thread bThread = new Thread(group, b);
		aThread.start();
		bThread.start();
		System.out.println("活动的线程数:" + group.activeCount());
		System.out.println("线程组的名称:" + group.getName());
	}
}

运行程序,控制台打印结果如下:

活动的线程数:2
ThreadName=Thread-3
ThreadName=Thread-2
线程组的名称:My-Thread-Group
ThreadName=Thread-3
ThreadName=Thread-2
ThreadName=Thread-3
ThreadName=Thread-2
......
线程对象关联线程组:多级关联

所谓的多级关联就是父对象中有子对象,子对象中再创建子对象,也就是出现孙对象的效果。

public class Main {
	public static void main(String[] args) {
		ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
		ThreadGroup group = new ThreadGroup(mainGroup, "A");
		Runnable runnable = new Runnable() {
			
			@Override
			public void run() {
				try {
					System.out.println("run method");
					Thread.sleep(10000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		Thread newThread = new Thread(group, runnable);
		newThread.setName("Z");
		newThread.start();
		ThreadGroup[] listGroup = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
		Thread.currentThread().getThreadGroup().enumerate(listGroup);
		System.out.println("main线程中有" + listGroup.length + "个子线程,名字:" + listGroup[0].getName());
		Thread[] listThread = new Thread[listGroup[0].activeCount()];
		listGroup[0].enumerate(listThread);
		System.out.println(listThread[0].getName());
	}
}

运行程序控制台打印结果如下:

run method
main线程中有1个子线程,名字:A
Z

此种写法在开发中不常见,太复杂不利于管理。


如果实例化线程组时不指定所属的线程组,则实例化的线程组归到当前线程对象所属的线程组中

public class Main {
	public static void main(String[] args) {
		System.out.println("当前线程名:" + Thread.currentThread().getName());
		System.out.println("所属线程组:" + Thread.currentThread().getThreadGroup().getName());
		System.out.println("线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount());
		ThreadGroup group = new ThreadGroup("New-group");
		System.out.println("线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount());
		ThreadGroup[] threadGroups = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
		Thread.currentThread().getThreadGroup().enumerate(threadGroups);
		for (int i = 0; i < threadGroups.length; i++) {
			System.out.println("第" + (i + 1) + "个线程组名字为:" + threadGroups[i].getName());
		}
		//如果实例化线程组时不指定所属的线程组,则实例化的线程组归到当前线程对象所属的线程组中
	}
}

运行以上程序,控制台打印结果如下:

当前线程名:main
所属线程组:main
线程组数量:0
线程组数量:1
第1个线程组名字为:New-group

获取根线程组

//获取根线程组
public class Main {
	public static void main(String[] args) {
		System.out.println("当前线程名:" + Thread.currentThread().getName());
		System.out.println("所属线程组:" + Thread.currentThread().getThreadGroup().getName());
		System.out.println("当前线程所属线程组的父线程组名:" + Thread.currentThread().getThreadGroup().getParent().getName());
		System.out.println("当前线程所属线程组的父线程组的父线程组名:" + Thread.currentThread().getThreadGroup().getParent().getParent().getName());
	}
}

控制台输出结果如下:

当前线程名:main
所属线程组:main
当前线程所属线程组的父线程组名:system
Exception in thread "main" java.lang.NullPointerException
	at com.umgsai.thread.thread66.Main2.main(Main2.java:9)

运行结果说明JVM的根线程组是system,再取其父线程组则抛出空指针异常。


线程组里加线程组

public class Main3 {
	public static void main(String[] args) {
		System.out.println("线程组名:" + Thread.currentThread().getThreadGroup().getName());
		System.out.println("线程组中活动线程数:" + Thread.currentThread().getThreadGroup().activeCount());
		System.out.println("线程组中线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount());
		ThreadGroup group = new ThreadGroup(Thread.currentThread().getThreadGroup(), "newGroup");
		System.out.println("线程组中线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount());
		System.out.println("父线程组名称:" + Thread.currentThread().getThreadGroup().getParent().getName());
	}
}

控制台输出结果如下:

线程组名:main
线程组中活动线程数:1
线程组中线程组数量:0
线程组中线程组数量:1
父线程组名称:system

组内的线程批量停止

public class MyThread extends Thread {
	public MyThread(ThreadGroup group, String name) {
		super(group, name);
	}
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "准备开始死循环了");
		while (!this.isInterrupted()) {
		}
		System.out.println(Thread.currentThread().getName() + "结束死循环了");
	}
}

public class Main {
	public static void main(String[] args) {
		try {
			ThreadGroup group = new ThreadGroup("My-group");
			for (int i = 0; i < 5; i++) {
				MyThread thread = new MyThread(group, "Thread-" + i);
				thread.start();
			}
			Thread.sleep(5000);
			group.interrupt();
			System.out.println("调用了interrupt方法");
		} catch (Exception e) {
			System.out.println("停了");
			e.printStackTrace();
		}
	}
}

控制台输出如下:

Thread-3准备开始死循环了
Thread-2准备开始死循环了
Thread-1准备开始死循环了
Thread-4准备开始死循环了
调用了interrupt方法
Thread-3结束死循环了
Thread-2结束死循环了
Thread-4结束死循环了
Thread-1结束死循环了
Thread-0结束死循环了

递归与非递归取组内对象

public class Main5 {
	public static void main(String[] args) {
		ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
		ThreadGroup groupA = new ThreadGroup(mainGroup, "A");
		Runnable runnable = new Runnable() {
			
			@Override
			public void run() {
				try {
					System.out.println("run Method");
					Thread.sleep(10000);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		ThreadGroup groupB = new ThreadGroup(groupA, "B");
		ThreadGroup[] groups = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
		//传入true取得其子组及子孙组
		Thread.currentThread().getThreadGroup().enumerate(groups, true);
		for (int i = 0; i < groups.length; i++) {
			if (groups[i] != null) {
				System.out.println(groups[i].getName());
			}
		}
		System.out.println("------");
		ThreadGroup[] groups2 = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
		Thread.currentThread().getThreadGroup().enumerate(groups2, false);
		for (int i = 0; i < groups2.length; i++) {
			if (groups2[i] != null) {
				System.out.println(groups2[i].getName());
			}
			
		}
	}
}

控制台打印结果如下:

A
B
------
A

使线程具有顺序性

public class MyThread extends Thread {
	private Object lock;
	private String showChar;
	private int showNumberPosition;
	private int printCount = 0;
	volatile private static int addNumber = 1;
	public MyThread(Object lock, String showChar, int showNumberPosition) {
		super();
		this.lock = lock;
		this.showChar = showChar;
		this.showNumberPosition = showNumberPosition;
	}
	@Override
	public void run() {
		try {
			synchronized (lock) {
				while (true) {
					if (addNumber % 3 == showNumberPosition) {
						System.out.println(Thread.currentThread().getName() + "-" + addNumber + "-" + showChar);
						lock.notifyAll();
						addNumber++;
						printCount++;
						if (printCount == 3) {
							break;
						}
					}else {
						lock.wait();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		Object lock = new Object();
		MyThread a = new MyThread(lock, "A", 1);
		MyThread b = new MyThread(lock, "B", 2);
		MyThread c = new MyThread(lock, "C", 0);
		a.start();
		b.start();
		c.start();
	}
}

控制台打印结果如下:

Thread-0-1-A
Thread-1-2-B
Thread-2-3-C
Thread-0-4-A
Thread-1-5-B
Thread-2-6-C
Thread-0-7-A
Thread-1-8-B
Thread-2-9-C

类SimpleDateFormat主要负责日期的转换与格式化,但在多线程的环境中,使用此类容易造成数据转换及处理的不准确,因为SimpleDateFormat类并不是线程安全的。

public class MyThread extends Thread {
    private SimpleDateFormat sdf;
    private String dateString;

    public MyThread(SimpleDateFormat sdf, String dateString) {
        super();
        this.sdf = sdf;
        this.dateString = dateString;
    }

    @Override
    public void run() {
        try {
            Date dateRef = sdf.parse(dateString);
            String newDateString = sdf.format(dateRef).toString();
            if (!newDateString.equals(dateString)) {
                System.out.println("ThreadName=" + this.getName()
                        +"报错了,日期字符串:" +dateString
                        +",转换成的日期为:"+newDateString);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
    	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String[] dateStringArray = new String[]{"2016-07-01", "2016-07-02", "2016-07-03", "2016-07-04", "2016-07-05", "2016-07-06", "2016-07-07", "2016-07-08", "2016-07-09", "2016-07-10"};
        MyThread[] threadArray = new MyThread[10];
        for (int i=0; i<threadArray.length; i++) {
            threadArray[i] = new MyThread(sdf, dateStringArray[i]);
        }
        for (int i=0; i<threadArray.length; i++) {
            threadArray[i].start();
        }
	}
}

运行程序,控制台打印结果如下:

Exception in thread "Thread-3" Exception in thread "Thread-5" ThreadName=Thread-8报错了,日期字符串:2016-07-09,转换成的日期为:2016-07-08
Exception in thread "Thread-1" Exception in thread "Thread-4" java.lang.NumberFormatException: empty String
	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1020)
	at java.lang.Double.parseDouble(Double.java:540)
	at java.text.DigitList.getDouble(DigitList.java:168)
	at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
	at java.text.DateFormat.parse(DateFormat.java:355)
ThreadName=Thread-6报错了,日期字符串:2016-07-07,转换成的日期为:2070-12-07
ThreadName=Thread-2报错了,日期字符串:2016-07-03,转换成的日期为:0010-12-07
ThreadName=Thread-7报错了,日期字符串:2016-07-08,转换成的日期为:0000-12-07
	at com.umgsai.thread.thread67.MyThread1.run(MyThread1.java:20)
Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: "66E16E16E1"
	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1250)
	at java.lang.Double.parseDouble(Double.java:540)
	at java.text.DigitList.getDouble(DigitList.java:168)
	at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
	at java.text.DateFormat.parse(DateFormat.java:355)
	at com.umgsai.thread.thread67.MyThread1.run(MyThread1.java:20)
java.lang.NumberFormatException: For input string: "66E"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Long.parseLong(Long.java:441)
	at java.lang.Long.parseLong(Long.java:483)
	at java.text.DigitList.getLong(DigitList.java:194)
	at java.text.DecimalFormat.parse(DecimalFormat.java:1316)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2088)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
	at java.text.DateFormat.parse(DateFormat.java:355)
	at com.umgsai.thread.thread67.MyThread1.run(MyThread1.java:20)
java.lang.NumberFormatException: For input string: "...7076"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Long.parseLong(Long.java:430)
	at java.lang.Long.parseLong(Long.java:483)
	at java.text.DigitList.getLong(DigitList.java:194)
	at java.text.DecimalFormat.parse(DecimalFormat.java:1316)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
	at java.text.DateFormat.parse(DateFormat.java:355)
	at com.umgsai.thread.thread67.MyThread1.run(MyThread1.java:20)
java.lang.NumberFormatException: For input string: "66E16E1"
	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1250)
	at java.lang.Double.parseDouble(Double.java:540)
	at java.text.DigitList.getDouble(DigitList.java:168)
	at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
	at java.text.DateFormat.parse(DateFormat.java:355)
	at com.umgsai.thread.thread67.MyThread1.run(MyThread1.java:20)

解决方法1:

public class DateUtil {
    public static String format(String formatPattern, Date date){
         return new SimpleDateFormat(formatPattern).format(date).toString();
    }
    
    public static Date parse(String formatPattern, String dateString) throws ParseException{
        return new SimpleDateFormat(formatPattern).parse(dateString);
    }
}

public class MyThread extends Thread {
    private String dateString;

    public MyThread(String dateString) {
        super();
        this.dateString = dateString;
    }

    @Override
    public void run() {
        try {
            Date dateRef = DateUtil.parse("yyyy-MM-dd", dateString);
            String newDateString = DateUtil.format("yyyy-MM-dd" ,dateRef).toString();
            if (!newDateString.equals(dateString)) {
                System.out.println("ThreadName=" + this.getName()
                        +"报错了,日期字符串:" +dateString
                        +",转换成的日期为:"+newDateString);
            }else{
            	System.out.println("转换正确");
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        String[] dateStringArray = new String[]{"2016-07-01", "2016-07-02", "2016-07-03", "2016-07-04", "2016-07-05", "2016-07-06", "2016-07-07", "2016-07-08", "2016-07-09", "2016-07-10"};
        MyThread[] threadArray = new MyThread2[10];
        for (int i=0; i<threadArray.length; i++) {
            threadArray[i] = new MyThread(dateStringArray[i]);
        }
        for (int i=0; i<threadArray.length; i++) {
            threadArray[i].start();
        }
	}
}

运行程序,控制台打印结果如下:

转换正确
转换正确
转换正确
转换正确
转换正确
转换正确
转换正确
转换正确
转换正确
转换正确

此时每个线程分别使用自己独立的SimpleDateFormat对象,不会出现线程安全问题。

解决方法2:

public class DateTools {
	private static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<>();
	public static SimpleDateFormat getSimpleDateFormat(String dateParttern) {
		SimpleDateFormat sdf = null;
		sdf = t1.get();
		if (sdf == null) {
			sdf = new SimpleDateFormat(dateParttern);
			t1.set(sdf);
		}
		return sdf;
	}
}

public class MyThread extends Thread {
    private String dateString;

    public MyThread(String dateString) {
        super();
        this.dateString = dateString;
    }

    @Override
    public void run() {
        try {
            Date dateRef = DateTools.getSimpleDateFormat("yyyy-MM-dd").parse(dateString);
            String newDateString = DateTools.getSimpleDateFormat("yyyy-MM-dd").format(dateRef).toString();
            if (!newDateString.equals(dateString)) {
                System.out.println("ThreadName=" + this.getName()
                        +"报错了,日期字符串:" +dateString
                        +",转换成的日期为:"+newDateString);
            }else{
            	System.out.println("转换正确");
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        String[] dateStringArray = new String[]{"2016-07-01", "2016-07-02", "2016-07-03", "2016-07-04", "2016-07-05", "2016-07-06", "2016-07-07", "2016-07-08", "2016-07-09", "2016-07-10"};
        MyThread[] threadArray = new MyThread[10];
        for (int i=0; i<threadArray.length; i++) {
            threadArray[i] = new MyThread(dateStringArray[i]);
        }
        for (int i=0; i<threadArray.length; i++) {
            threadArray[i].start();
        }
	}
}

运行程序,控制台打印结果如下:

转换正确
转换正确
转换正确
转换正确
转换正确
转换正确
转换正确
转换正确
转换正确
转换正确

线程中出现异常的处理

在Java多线程中,可以对多线程中的异常进行“捕捉”,使用的是UncaughtExceptionHandler类。

public class MyThread extends Thread {
	@Override
	public void run() {
		String username = null;
		System.out.println(username.hashCode());
	}
	
	public static void main(String[] args) {
		MyThread t1 = new MyThread();
		t1.setName("线程1");
		t1.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
			
			@Override
			public void uncaughtException(Thread t, Throwable e) {
				System.out.println(t.getName() + "出现了异常");
				e.printStackTrace();
			}
		});
		t1.start();
		MyThread t2 = new MyThread();
		t2.setName("线程2");
		t2.start();
	}
}

运行程序,控制台打印结果如下:

Exception in thread "线程2" 线程1出现了异常
java.lang.NullPointerException
	at com.umgsai.thread.thread69.MyThread.run(MyThread.java:7)
java.lang.NullPointerException
	at com.umgsai.thread.thread69.MyThread.run(MyThread.java:7)

setUncaughtExceptionHandler()是给指定的线程对象设置异常处理器。在Thread类中可以使用setDefaultUncaughtExceptionHandler()方法对所有线程对象设置异常处理器。

public class MyThread extends Thread {
	@Override
	public void run() {
		String username = null;
		System.out.println(username.hashCode());
	}
	
	public static void main(String[] args) {
		MyThread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
					
					@Override
					public void uncaughtException(Thread t, Throwable e) {
						System.out.println(t.getName() + "出现了异常");
						e.printStackTrace();
					}
				});
		MyThread t1 = new MyThread();
		t1.setName("线程1");
		t1.start();
		MyThread t2 = new MyThread();
		t2.setName("线程2");
		t2.start();
	}
}

运行程序,控制台打印结果如下:

线程1出现了异常
线程2出现了异常
java.lang.NullPointerException
	at com.umgsai.thread.thread69.MyThread.run(MyThread.java:7)
java.lang.NullPointerException
	at com.umgsai.thread.thread69.MyThread.run(MyThread.java:7)

线程组内处理异常

public class MyThread extends Thread {
	private String num;
	public MyThread(ThreadGroup group, String name, String num) {
		super(group, name);
		this.num = num;
	}
	@Override
	public void run() {
		int numInt = Integer.parseInt(num);
		while (true) {
			System.out.println(Thread.currentThread().getName() + "死循环中");
		}
	}
	
	public static void main(String[] args) {
		ThreadGroup group = new ThreadGroup("线程组1");
		MyThread[] myThreads = new MyThread[10];
		for (int i = 0; i < myThreads.length; i++) {
			myThreads[i] = new MyThread(group, "线程" + i, "" + i);
			myThreads[i].start();
		}
		MyThread myThread = new MyThread(group, "报错线程", "a");
		myThread.start();
	}
}

运行程序后,出错的线程抛出异常后停止,其他线程仍然正常执行。

如果要使一个线程抛异常后同组内其他线程都停止执行可以做如下修改:

public class MyThreadGroup extends ThreadGroup {
	public MyThreadGroup(String name) {
		super(name);
	}
	@Override
	public void uncaughtException(Thread t, Throwable e) {
		super.uncaughtException(t, e);
		this.interrupt();
	}
}

package com.umgsai.thread.thread71;

public class MyThread extends Thread {
	private String num;
	public MyThread(ThreadGroup group, String name, String num) {
		super(group, name);
		this.num = num;
	}
	@Override
	public void run() {
		int numInt = Integer.parseInt(num);
		while (! this.isInterrupted()) {
			System.out.println(Thread.currentThread().getName() + "死循环中");
		}
	}
	
	
	public static void main(String[] args) {
		MyThreadGroup group = new MyThreadGroup("线程组1");
		MyThread[] myThreads = new MyThread[10];
		for (int i = 0; i < myThreads.length; i++) {
			myThreads[i] = new MyThread(group, "线程" + i, "" + i);
			myThreads[i].start();
		}
		MyThread myThread = new MyThread(group, "报错线程", "a");
		myThread.start();
	}
}

运行程序,报错线程抛出异常后,其他线程都停止了执行。


线程异常处理的传递

public class MyThread extends Thread {
	private String num = "a";
	public MyThread() {
		super();
	}
	public MyThread(ThreadGroup group, String name) {
		super(group, name);
	}
	@Override
	public void run() {
		int numInt = Integer.parseInt(num);
		System.out.println("在线程中打印:" + (numInt));
	}
}

public class ObjectUncaughtExceptionHandler implements UncaughtExceptionHandler {

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		System.out.println("对象的异常处理");
		e.printStackTrace();
	}

}

public class StateUncaughtExceptionHandler implements UncaughtExceptionHandler {

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		System.out.println("静态的异常处理");
		e.printStackTrace();
	}
}

public class Main {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
		myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
		myThread.start();
	}
}

运行程序,控制台打印结果如下:

对象的异常处理
java.lang.NumberFormatException: For input string: "a"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:492)
	at java.lang.Integer.parseInt(Integer.java:527)
	at com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)

对以上程序做如下修改:

public class Main {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
		//myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
		myThread.start();
	}
}

重新运行程序,控制台打印结果如下:

静态的异常处理
java.lang.NumberFormatException: For input string: "a"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:492)
	at java.lang.Integer.parseInt(Integer.java:527)
	at com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)

继续修改以上代码:

public class MyThreadGroup extends ThreadGroup {

	public MyThreadGroup(String name) {
		super(name);
	}
	@Override
	public void uncaughtException(Thread t, Throwable e) {
		super.uncaughtException(t, e);
		System.out.println("线程组的异常处理");
		e.printStackTrace();
	}
}

public class Main {
	public static void main(String[] args) {
		MyThreadGroup group = new MyThreadGroup("我的线程组");
		MyThread myThread = new MyThread(group, "我的线程");
		MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
		myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
		myThread.start();
	}
}

运行程序,控制台打印结果如下:

对象的异常处理
java.lang.NumberFormatException: For input string: "a"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:492)
	at java.lang.Integer.parseInt(Integer.java:527)
	at com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)

继续修改以上代码:

public class Main {
	public static void main(String[] args) {
		MyThreadGroup group = new MyThreadGroup("我的线程组");
		MyThread myThread = new MyThread(group, "我的线程");
		MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
		//myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
		myThread.start();
	}
}

运行程序,控制台打印结果如下:

静态的异常处理
java.lang.NumberFormatException: For input string: "a"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:492)
	at java.lang.Integer.parseInt(Integer.java:527)
	at com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)
线程组的异常处理
java.lang.NumberFormatException: For input string: "a"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:492)
	at java.lang.Integer.parseInt(Integer.java:527)
	at com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)

继续修改以上代码:

public class Main {
	public static void main(String[] args) {
		MyThreadGroup group = new MyThreadGroup("我的线程组");
		MyThread myThread = new MyThread(group, "我的线程");
		//MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
		//myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
		myThread.start();
	}
}

运行程序,控制台打印结果如下:

Exception in thread "我的线程" java.lang.NumberFormatException: For input string: "a"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:492)
	at java.lang.Integer.parseInt(Integer.java:527)
	at com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)
java.lang.NumberFormatException: For input string: "a"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
线程组的异常处理
	at java.lang.Integer.parseInt(Integer.java:492)
	at java.lang.Integer.parseInt(Integer.java:527)
	at com.umgsai.thread.thread72.MyThread.run(MyThread.java:13)
原文地址:https://www.cnblogs.com/umgsai/p/5600111.html