相关链接:
【Java多线程编程核心技术】1.Java多线程技能-笔记总结
【Java多线程编程核心技术】2.对象及变量的并发访问(上)-笔记总结
【Java多线程编程核心技术】2.对象及变量的并发访问(下)-笔记总结
【Java多线程编程核心技术】3.线程间通信 -笔记总结
【Java多线程编程核心技术】4.Lock的使用-笔记总结
【Java多线程编程核心技术】5.定时器Timer-笔记总结
【Java多线程编程核心技术】6.单例模式与多线程-笔记总结
【Java多线程编程核心技术】7.拾遗增补-笔记总结
线程的状态
线程对象在不同的运行时期有不同的状态,状态信息就存在于State枚举类中
这些状态之间某些是可双向切换的,比如waiting和running状态之间可以循环地进行切换
有些事单向切换的,比如线程销毁后并不能自动进入Running状态
线程组
可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程。
线程组作用:批量管理线程或线程组对象,有效地对线程或线程组对象进行组织
线程对象管理线程组:1级关联
1级关联:父对象中有子对象,但不创建子孙对象。
package test;
import extthread.ThreadA;
import extthread.ThreadB;
public class Run {
public static void main(String[] args) {
ThreadA aRunnable = new ThreadA();
ThreadB bRunnable = new ThreadB();
ThreadGroup group = new ThreadGroup("高洪岩的线程组");
Thread aThread = new Thread(group, aRunnable); //将 aThread线程归属到group线程组中
Thread bThread = new Thread(group, bRunnable);
aThread.start();
bThread.start();
System.out.println("活动的线程数为:" + group.activeCount());
System.out.println("线程组的名称为:" + group.getName());
}
}
Thread aThread = new Thread(group, aRunnable); //将 aThread线程归属到group线程组中
线程对象管理线程组:多级关联
多级关联:父对象中有子对象,子对象中再创建子对象,也就是出现子孙对象的效果。(代码知识点后面章节会覆盖)
线程组自动归属特性
public class Run {
public static void main(String[] args) {
System.out.println("A处线程:"+Thread.currentThread().getName()+" 中有线程组数量:"+Thread.currentThread().getThreadGroup().activeGroupCount());
ThreadGroup group=new ThreadGroup("新的组");
System.out.println("A处线程:"+Thread.currentThread().getName()+" 中有线程组数量:"+Thread.currentThread().getThreadGroup().activeGroupCount());
ThreadGroup[] threadGroup=new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
Thread.currentThread().getThreadGroup().enumerate(threadGroup);
for (int i = 0; i < threadGroup.length; i++) {
System.out.println("第一个线程组名称为:"+threadGroup[i].getName());
}
}
}
输出结果:
A处线程:main 中有线程组数量:0
A处线程:main 中有线程组数量:1
第一个线程组名称为:新的组
activeGroupCount():取得当前线程组对象中的子线程组数量
enumerate():将线程组中的子线程组以复制的形式拷贝到ThreadGroup[]数组对象中
在实例化一个ThreadGroup线程组x时,如果不指定所属的线程组,则x线程组自动归到当前线程对象所属的线程组中。
获取根线程组
Thread.currentThread().getThreadGroup().getParent() //输出:system
Thread.currentThread().getThreadGroup().getPatent().getParent().getParent() //报空指针异常
JVM的根线程组就是system,再取其父线程组则出现空异常
线程组里加线程组
ThreadGroup newGroup = new ThreadGroup(Thread.currentThread()
.getThreadGroup(), "newGroup");
显式的方式在一个线程组(此处为main线程组)中添加一个名称为“newGroup”子线程组
组内的线程批量停止
ThreadGroup group = new ThreadGroup("我的线程组");
for (int i = 0; i < 5; i++) {
MyThread thread = new MyThread(group, "线程" + (i + 1));
thread.start();
}
Thread.sleep(5000);
group.interrupt();
System.out.println("调用了interrupt()方法");
线程组中所有的线程均处于被调用interrupt()方法的状态中,批量执行。
递归与非递归取得组内对象
Thread.currentThread().getThreadGroup().enumerate(listGroup1, true); //递归
Thread.currentThread().getThreadGroup().enumerate(listGroup2, false);//非递归
递归取得组内对象:复制子线程组及其子孙线程组
非递归取得组内对象:只复制子线程组
SimpleDateFormat非线程安全
类SimpleDateFormat主要负责日期的转换与格式化,SimpleDateFormat类在多线程环境中,容易造成数据转换及处理的不准确,因为SimpleDateFormat类并不是线程安全的
解决异常方法:通过ThreadLocal类解决
ThreadLocal类详解:http://blog.csdn.net/yangdongchuan1995/article/details/78578337
package extthread;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import tools.DateTools;
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 = 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);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
package tools;
import java.text.SimpleDateFormat;
public class DateTools {
private static ThreadLocal tl = new ThreadLocal();
public static SimpleDateFormat getSimpleDateFormat(String datePattern) {
SimpleDateFormat sdf = null;
sdf = tl.get();
if (sdf == null) {
sdf = new SimpleDateFormat(datePattern);
tl.set(sdf);
}
return sdf;
}
}
package test.run;
import java.text.SimpleDateFormat;
import extthread.MyThread;
public class Test {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String[] dateStringArray = new String[] { "2000-01-01", "2000-01-02",
"2000-01-03", "2000-01-04", "2000-01-05", "2000-01-06",
"2000-01-07", "2000-01-08", "2000-01-09", "2000-01-10" };
MyThread[] threadArray = new MyThread[10];
for (int i = 0; i < 10; i++) {
threadArray[i] = new MyThread(sdf, dateStringArray[i]);
}
for (int i = 0; i < 10; i++) {
threadArray[i].start();
}
}
}
输出结果:(什么都不输出,因为没报错)
线程中出现异常的处理
package controller;
import java.lang.Thread.UncaughtExceptionHandler;
import extthread.MyThread;
public class Main2 {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.setName("线程t1");
t1.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("线程:" + t.getName() + " 出现了异常:");
e.printStackTrace();
}
});
// MyThread
// .setDefaultUncaughtExceptionHandler(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("线程t2");
t2.start();
}
}
setUncaughtExceptionHandler():对指定的线程对象设置默认的异常处理器
setDefaultUncaughtExceptionHandler():为指定线程类的所有线程对象设置默认的异常处理器
线程组内处理异常
package extthread;
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() == false) {
System.out.println("死循环中:" + Thread.currentThread().getName());
}
}
}
package extthreadgroup;
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 test.run;
import extthread.MyThread;
import extthreadgroup.MyThreadGroup;
public class Run {
public static void main(String[] args) {
MyThreadGroup group = new MyThreadGroup("我的线程组");
MyThread[] myThread = new MyThread[3];
for (int i = 0; i < myThread.length; i++) {
myThread[i] = new MyThread(group, "线程" + (i + 1), "1");
myThread[i].start();
}
MyThread newT = new MyThread(group, "报错线程", "a");
newT.start();
}
}
输出结果:
死循环中:线程1
死循环中:线程1
死循环中:线程1
死循环中:线程1
死循环中:线程1
死循环中:线程1
死循环中:线程2
死循环中:线程3
死循环中:线程3
死循环中:线程3
死循环中:线程3
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 extthread.MyThread.run(MyThread.java:14)
重现uncaughtException方法处理组内线程中断行为时,每个线程对象中的run()方法内部不要有异常catch语句
线程异常处理的传递
public static void main(String[] args) {
MyThread myThread = new MyThread();
// 对象
myThread
.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
// 类
MyThread
.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
myThread.start();
}
在未设置线程组时,setUncaughtExceptionHandler()先捕获异常,在前者未配置的情况下,才让setDefaultUncaughtExceptionHandler()进行捕获异常。
package extthread;
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 + 1));
}
}
package extthreadgroup;
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();
}
}
package test.extUncaughtExceptionHandler;
import java.lang.Thread.UncaughtExceptionHandler;
public class ObjectUncaughtExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("对象的异常处理");
e.printStackTrace();
}
}
package test.extUncaughtExceptionHandler;
import java.lang.Thread.UncaughtExceptionHandler;
public class StateUncaughtExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("静态的异常处理");
e.printStackTrace();
}
}
public static void main(String[] args) {
MyThreadGroup group = new MyThreadGroup("我的线程组");
MyThread myThread = new MyThread(group, "我的线程");
// 对象
myThread
.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
// 类
MyThread
.setDefaultUncaughtExceptionHandler(new
StateUncaughtExceptionHandler());
myThread.start();
}
在设置了线程组以后,也同样是setUncaughtExceptionHandler()先捕获异常,
再者是线程组的异常处理
将//super.uncaughtException(t, e); 注释取消后, 线程组的异常处理与静态的异常处理 能一起输出。