Java多线程编程核心技术---拾遗增补
2017-01-09 14:07
896 查看
线程状态验证
运行程序控制台输出结果如下:
运行程序,控制台打印结果如下:
线程对象关联线程组:1级关联
所谓的1级关联就是父对象中有子对象,但是并不创建孙对象。
运行程序,控制台打印结果如下:
线程对象关联线程组:多级关联
所谓的多级关联就是父对象中有子对象,子对象中再创建子对象,也就是出现孙对象的效果。
运行程序控制台打印结果如下:
此种写法在开发中不常见,太复杂不利于管理。
如果实例化线程组时不指定所属的线程组,则实例化的线程组归到当前线程对象所属的线程组中
运行以上程序,控制台打印结果如下:
获取根线程组
控制台输出结果如下:
运行结果说明JVM的根线程组是system,再取其父线程组则抛出空指针异常。
线程组里加线程组
控制台输出结果如下:
组内的线程批量停止
控制台输出如下:
递归与非递归取组内对象
控制台打印结果如下:
使线程具有顺序性
控制台打印结果如下:
类SimpleDateFormat主要负责日期的转换与格式化,但在多线程的环境中,使用此类容易造成数据转换及处理的不准确,因为SimpleDateFormat类并不是线程安全的。
运行程序,控制台打印结果如下:
解决方法1:
运行程序,控制台打印结果如下:
此时每个线程分别使用自己独立的SimpleDateFormat对象,不会出现线程安全问题。
解决方法2:
运行程序,控制台打印结果如下:
线程中出现异常的处理
在Java多线程中,可以对多线程中的异常进行“捕捉”,使用的是UncaughtExceptionHandler类。
运行程序,控制台打印结果如下:
setUncaughtExceptionHandler()是给指定的线程对象设置异常处理器。在Thread类中可以使用setDefaultUncaughtExceptionHandler()方法对所有线程对象设置异常处理器。
运行程序,控制台打印结果如下:
线程组内处理异常
运行程序后,出错的线程抛出异常后停止,其他线程仍然正常执行。
如果要使一个线程抛异常后同组内其他线程都停止执行可以做如下修改:
运行程序,报错线程抛出异常后,其他线程都停止了执行。
线程异常处理的传递
运行程序,控制台打印结果如下:
对以上程序做如下修改:
重新运行程序,控制台打印结果如下:
继续修改以上代码:
运行程序,控制台打印结果如下:
继续修改以上代码:
运行程序,控制台打印结果如下:
继续修改以上代码:
运行程序,控制台打印结果如下:
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)
相关文章推荐
- Java多线程编程核心技术---拾遗增补
- java多线程编程核心技术7-拾遗增补
- 【Java多线程编程核心技术】7.拾遗增补-笔记总结
- 二、java多线程编程核心技术之(笔记)——如何停止线程?
- Java多线程编程核心技术--Lock的使用(一)
- Java多线程编程核心技术--定时器
- Java多线程编程核心技术--Lock的使用(一)
- Java多线程编程核心技术--定时器
- Java多线程编程核心技术---Java多线程技能
- Java多线程编程核心技术(第五章定时器Timer笔记)
- Java多线程编程核心技术---学习分享
- Java多线程编程核心技术---学习分享
- 好读书不求甚解(一)Java多线程编程核心技术
- java多线程编程核心技术1-Thread基础知识
- Java多线程编程核心技术---对象及变量的并发访问(一)
- Java多线程编程核心技术---单例模式与多线程
- Java多线程编程核心技术---对象及变量的并发访问(一)
- Java多线程编程核心技术——生产者消费者模型
- Java多线程编程核心技术---Java多线程技能
- Java多线程编程核心技术---线程间通信(二)