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)
Java多线程编程核心技术---拾遗增补的更多相关文章
- Java多线程编程核心技术
Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...
- 《Java多线程编程核心技术》知识梳理
<Java多线程编程核心技术> @author ergwang https://www.cnblogs.com/ergwang/ 文章末尾附pdf和png下载链接 第1章 Java多线程技 ...
- Java多线程编程核心技术---学习分享
继承Thread类实现多线程 public class MyThread extends Thread { @Override public void run() { super.run(); Sys ...
- Java多线程编程核心技术---对象及变量的并发访问(二)
数据类型String的常量池特性 在JVM中具有String常量池缓存的功能. public class Service { public static void print(String str){ ...
- 《Java多线程编程核心技术》推荐
写这篇博客主要是给猿友们推荐一本书<Java多线程编程核心技术>. 之所以要推荐它,主要因为这本书写得十分通俗易懂,以实例贯穿整本书,使得原本抽象的概念,理解起来不再抽象. 只要你有一点点 ...
- 《java多线程编程核心技术》(一)使用多线程
了解多线程 进程和多线程的概念和线程的优点: 提及多线程技术,不得不提及"进程"这个概念.百度百科对"进程"的解释如下: 进程(Process)是计算机中的程序 ...
- 《Java 多线程编程核心技术》- 笔记
作为业务开发人员,能够在工作中用到的技术其实不多.虽然平时老是说什么,多线程,并发,注入,攻击!但是在实际工作中,这些东西不见得用得上.因为,我们用的框架已经把这些事做掉了. 比如web开发,外面有大 ...
- Thread.currentThread()和this的区别——《Java多线程编程核心技术》
前言:在阅读<Java多线程编程核心技术>过程中,对书中程序代码Thread.currentThread()与this的区别有点混淆,这里记录下来,加深印象与理解. 具体代码如下: pub ...
- Java多线程编程核心技术(三)多线程通信
线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时 ...
随机推荐
- HTTP协议学习---(九)cookie
Cookie是HTTP协议中非常重要的东西, 之前拜读了Fish Li 写的[细说Cookie], 让我学到了很多东西.Fish的这篇文章写得太经典了. 所以我这篇文章就没有太多内容了. 最近我打算写 ...
- Fiddler Post Debug
Content-Type: application/json; charset="UTF-8"
- 【BZOJ-4561】圆的异或并 set + 扫描线
4561: [JLoi2016]圆的异或并 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 254 Solved: 118[Submit][Statu ...
- 【BZOJ-4521】手机号码 数位DP
4521: [Cqoi2016]手机号码 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 303 Solved: 194[Submit][Status ...
- Android成长日记-LogCat
1. Log日志级别 Log.v(tag,messag) //verbose模式,打印最详细的日志输出颜色为黑色 Log.d(tag,messag) //debug级别的日志,颜色为蓝色 Log.i( ...
- 洛谷P1629 邮递员送信
题目描述 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N.由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间.这个邮递员每 ...
- shell命令date
某个标准时间转换为unix时间戳 date -d '2015-10-20 15:07:02' +%s unix时间戳转换为对应的标准时间 date -d @1445324822 date " ...
- python使用cookielib库示例分享
Python中cookielib库(python3中为http.cookiejar)为存储和管理cookie提供客户端支持,下面是使用示例 该模块主要功能是提供可存储cookie的对象.使用此模块捕获 ...
- POJ 2240 - Arbitrage(bellman_ford & floyd)
题意: 给出一些货币和货币之间的兑换比率,问是否可以使某种货币经过一些列兑换之后,货币值增加. 举例说就是1美元经过一些兑换之后,超过1美元.可以输出Yes,否则输出No. 分析: 首先我们要把货币之 ...
- kali linux 2.0安装sublime text 2
第一种方法:Download the Sublime Text 2 & Extract it:32位:$ wget http://c758482.r82.cf2.rackcdn.com/Sub ...