[笔记][Java7并发编程实战手册][后补]1.线程管理
2015-10-14 22:48
453 查看
[笔记][Java7并发编程实战手册]系列目录
本章 是补充章节(学的时候跳过了这一章节),简单的就不写程序了.直接把笔记总结.
线程信息的获取和设置
线程的中断
线程中断的控制
线程的休眠和恢复
等待线程的终止
守护线程的创建和运行
线程中不可空异常的处理
线程局部变量的使用
线程的分组
线程组中不可空异常的处理
使用工厂类创建线程
只一系列任务的同时运行,如果电脑有多个处理器或者有一个多核处理器,这个同时性是真正意义的并发,但是一台电脑只有一个单核处理器,这个同时性并不是真正的并发.
进程级(Process_level)并发:
在windows中,同时可看电视,听歌,这样的是进程级并发
线程(Thread)
在一个进程内可以有多个同时进行的任务
并行
书上说得有几种,把我搞蒙了,我觉得:并发是同时间执行的线程,并发是几个线程可以一起执行?
new Thread(Runnable).start() 可开启线程
ID:线程的唯一标识符
Name:线程名称
Priority:线程优先级,从1 到 10,1是最低级,一般不推荐修改线程的优先级
Status:线程的状态.有: new、runnable、blocked、waiting、time waiting或者terminated
Thread类的属性存储了线程的所有信息,并且线程的id和status不能手动更改。如果你是实现 Runnable接口,那么可以通过 Thread的静态方法currentThread()来获取Thread对象
中断机制: 可以用来结束一个线程. 这种机制要求线程检测它是否被中断了,然后决定是不是相应这个中断请求.线程运行忽略中断请求并且继续执行.
本节将学习如何将一个线程 中断.(对于中断的机制,其实还是有点难的.需要写一下)
* 总结 *
难就难在,中断的代码相关代码,大部分都是原生代码,看到怎么实现的.
线程在休眠中,如果被中断 会抛出InterruptedException异常.捕获这个异常,通过跳出循环的方式先 run方法体执行完成.
外部设置 中断. 如果线程没有被休眠,可以通过 thread.isInterrupted() 来获取线程的中断状态.
还可以使用 Thread的静态方法 interrupted() 来判断是否被中断
interrupted 和 isInterrupted() :的区别,前者,会清除 中断状态.也就是说,如果外部设置了中断状态,调用interrupted的时候,返回true,同时会把中断状态清除为false
在递归循环的复杂调用中.(run方法中调用了多个方法.可以通过 在 多个方法中. 判断是否被中断了.然后手动的 抛出一个中断异常,在run中捕获这个异常,最终让任务结束)
* 某一次运行结果 *
* 结果说明 *
通过中断异常能捕获到 线程被设置为了中断.我猜测可能是. 因为线程在休眠中,然后又被设置了中断请求,然后run中肯定不能被执行到的.所以 休眠方法就抛出了一个中断异常,表示该线程已经被中断了.
休眠: 使用TimeUnit.SECONDS.sleep(1)是线程休眠1秒; 能让线程让出cpu执行时钟指令,在这个期间线程是不占用资源的,并且不占用cpu时钟的,所以cpu可以去执行其他的任务.TimeUnit.SECONDS.sleep(1) 也是包装了Thread.sleep(ms, ns)方法.
恢复: 等待休眠时间结束后,该线程又拥有了cpu时钟执行权,线程恢复.
thread的yield()方法,线程让步,让出当前线程的cpu时钟,但是又可能下一次还是让当前线程获得执行权,这个也是 和 休眠的一个区别.
join() : 等待线程的终止
守护线程(daemon) : 这种线程的优先级很低,通常来说一个程序中没有其他线程运行的时候,守护线程才运行.当守护线程是程序中唯一的线程的时候,守护线程结束后,jvm也就结束了.
因为这种特性,守护线程通常用来作为统一程序中普通线程(也称为用户线程)的服务提供者.它通常是无线循环的,以等待服务请求或则执行线程的任务.因此他们不能做重要的工作,因为不知道守护线程什么时候能获取cpu时钟指令,也有可能随时结束.
好把.我的疑问:
优先级低,不知道何时能获取cpu始终指令我能理解,但是说 一个程序中没有其他线程运行的时候,守护线程才运行? 是什么意思
* 总结 *
作为守护线程的 线程,要在该线程start前设置.
守护线程 会一直在后台运行,如果没有任何用户线程运行的时候,守护线程也会 结束.
isDaemon() : 获取是否是守护线程
* 一部分运行结果 *
* 结果说明 *
我最开始按照书上的例子,使用ArrayDeque来作为存储元素的队列,最后发现守护线程获取到的大小一直是0,然后我把守护线程休眠,就能获取到非0的队列. 这个就是一个线程问题了. 所以我觉得书上的列子是错误的结论. 然后使用 线程安全的队列(就是上面的示例),也只证实了.守护线程 会随着没有用户线程的时候跟着消失! 不知道是不是我的机器性能太好的缘故.书上的例子 没有办法重现证书说的是正确的.
非运行时异常(Checked Exception):这种异常必须在方法声明throws语句.或则在方法体中捕获
运行时异常(Unchecket Exception): 这种感异常 不必抛出,也可以捕获.
在run方法中,不支持抛出异常.所以 如果出现了在运行时异常,你不捕获(一般不仔细看api是不会知道的).默认是在控制台打印. 好在java提供了另一种在线程中捕获运行时异常的一种机制.
implements Thread.UncaughtExceptionHandler 类
在线程start前设置异常处理器 thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler);
这种捕获异常的方法.只可能是 运行时异常.原理肯定是 try 了下,然后把线程对象和异常对象回调给处理器的.( 不过短时间没有找到相关的源码)
也可以使用静态方法 Thread.setDefaultUncaughtExceptionHandler(new MyExHander()); 设置异常处理器
jvm调用查找异常处理器的顺序: 线程对象设置的 –> 线程组(ThreadGroup的) –> 最后是上面讲的默认的异常处理器
* 运行结果 *
很简单的使用,就不示例了.伪代码,把loc 用ThreadLocal来包装,并初始化. 而不是使用private Date date;
InheritableThreadLocal : 也是一种局部变量,不过它是用于给子线程 获取父线程的 局部变量的.假如:A线程创建了B线程.线程B的局部变量和A的局部变量是一样的.也可以覆盖childValue()方法,这个方法用来初始化子线程在线程局部变量中的值.它使用父线程在线程局部变量中的值作为参数传入.
ThreadGroup(线程组): 表示一组线程,可以包含线程对象,也可以包含线程组对象,它是一个树形结构.
在某些情况下,线程分组比较好控制,比如在多个线程运行中,你要控制他们.只需要一个单一的操作就能达到效果.
好把.看示例和运行结果,原来线程分组就是这样使用的.但是在以下的示例中,其实有弊端的.前面已经讲到过了, 中断:当线程在活动之前或活动期间处于正在等待、休眠或占用状态且该线程被中断时,抛出该异常InterruptedException .这样不在这些状态的时候 就没招了.然而不是还有一种方法么 就是通过检测是否中断
前面也有讲到,那么在下面的示例中 其实就很难运用到线程分组用组来操作线程了. 其他的我也没有想通.
* 某一次运行结果 *
extends ThreadGroup
重写 uncaughtException(Thread t, Throwable e) 方法.只要该线程组中有抛出异常的,该方法就会被调用
* 运行结果 *
本章 是补充章节(学的时候跳过了这一章节),简单的就不写程序了.直接把笔记总结.
本章内容包括
线程的创建和运行线程信息的获取和设置
线程的中断
线程中断的控制
线程的休眠和恢复
等待线程的终止
守护线程的创建和运行
线程中不可空异常的处理
线程局部变量的使用
线程的分组
线程组中不可空异常的处理
使用工厂类创建线程
1.1.简介
并发(Concurrency):只一系列任务的同时运行,如果电脑有多个处理器或者有一个多核处理器,这个同时性是真正意义的并发,但是一台电脑只有一个单核处理器,这个同时性并不是真正的并发.
进程级(Process_level)并发:
在windows中,同时可看电视,听歌,这样的是进程级并发
线程(Thread)
在一个进程内可以有多个同时进行的任务
并行
书上说得有几种,把我搞蒙了,我觉得:并发是同时间执行的线程,并发是几个线程可以一起执行?
1.2.线程的创建和运行
implements Runnable 接口 或则 extends Thread类,并实现或则重写run方法.new Thread(Runnable).start() 可开启线程
1.3.线程信息的获取和设置
Thread类的一些属性:ID:线程的唯一标识符
Name:线程名称
Priority:线程优先级,从1 到 10,1是最低级,一般不推荐修改线程的优先级
Status:线程的状态.有: new、runnable、blocked、waiting、time waiting或者terminated
Thread类的属性存储了线程的所有信息,并且线程的id和status不能手动更改。如果你是实现 Runnable接口,那么可以通过 Thread的静态方法currentThread()来获取Thread对象
1.4.线程的中断
一个Java程序,如果不止一个执行线程,当所有的线程都运行结束的时候,这个Java程序才能运行结束: 更准确的来说是 所有的非守护线程运行结束时,或则其中一个线程调用了System.exit()方法时,这个Java程序才运行结束. 如果你想终止一个程序,或则程序的某个用户视图取消线程对象正则运行的任务,就需要结束这个线程.中断机制: 可以用来结束一个线程. 这种机制要求线程检测它是否被中断了,然后决定是不是相应这个中断请求.线程运行忽略中断请求并且继续执行.
本节将学习如何将一个线程 中断.(对于中断的机制,其实还是有点难的.需要写一下)
* 总结 *
难就难在,中断的代码相关代码,大部分都是原生代码,看到怎么实现的.
线程在休眠中,如果被中断 会抛出InterruptedException异常.捕获这个异常,通过跳出循环的方式先 run方法体执行完成.
外部设置 中断. 如果线程没有被休眠,可以通过 thread.isInterrupted() 来获取线程的中断状态.
还可以使用 Thread的静态方法 interrupted() 来判断是否被中断
interrupted 和 isInterrupted() :的区别,前者,会清除 中断状态.也就是说,如果外部设置了中断状态,调用interrupted的时候,返回true,同时会把中断状态清除为false
在递归循环的复杂调用中.(run方法中调用了多个方法.可以通过 在 多个方法中. 判断是否被中断了.然后手动的 抛出一个中断异常,在run中捕获这个异常,最终让任务结束)
示例
/** * Created by zhuqiang on 2015/10/12 0012. */ public class Client { public static void main(String[] args){ Thread thread = new Thread(new Task()); thread.start(); //休眠3秒后发起中断请求 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { System.out.println("出错了"); e.printStackTrace(); } thread.interrupt(); System.out.println("请求中断:"); } } class Task implements Runnable{ @Override public void run() { boolean flag = true; Thread thread = Thread.currentThread(); while (flag){ System.out.println(thread.getName()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("是否被中断1 : " + thread.isInterrupted()); // 这个结果是fals flag = false; //要注意这里的坑. 在休眠中,如果线程被中断会被抛出 } if(thread.isInterrupted()){ //是否被中断 System.out.println("是否被中断2 : " + thread.isInterrupted()); // 把上面休眠的代码注释掉,能看到这个结果是 true flag = false; } } } }
* 某一次运行结果 *
Thread-0 Thread-0 Thread-0 请求中断: java.lang.InterruptedException: sleep interrupted 是否被中断1 : false at java.lang.Thread.sleep(Native Method) at java.lang.Thread.sleep(Thread.java:340) at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) at java7Concurrency.sync1_4.Task.run(Client.java:34) at java.lang.Thread.run(Thread.java:745)
* 结果说明 *
通过中断异常能捕获到 线程被设置为了中断.我猜测可能是. 因为线程在休眠中,然后又被设置了中断请求,然后run中肯定不能被执行到的.所以 休眠方法就抛出了一个中断异常,表示该线程已经被中断了.
1.5.线程中断的控制
线程的中断 中总结了1.6.线程的休眠和恢复
好吧,在1.4中就已经用到了 休眠,果然是补的章节啊.休眠: 使用TimeUnit.SECONDS.sleep(1)是线程休眠1秒; 能让线程让出cpu执行时钟指令,在这个期间线程是不占用资源的,并且不占用cpu时钟的,所以cpu可以去执行其他的任务.TimeUnit.SECONDS.sleep(1) 也是包装了Thread.sleep(ms, ns)方法.
恢复: 等待休眠时间结束后,该线程又拥有了cpu时钟执行权,线程恢复.
thread的yield()方法,线程让步,让出当前线程的cpu时钟,但是又可能下一次还是让当前线程获得执行权,这个也是 和 休眠的一个区别.
1.7.等待线程的终止
在一些情形下,比如 需要先初始化一些资源,初始化完成之后,再继续执行.这个时候 我们就需要等待线程终止再执行程序的其他任务. 可以使用 thread 的 join()方法. 示例就不写了,在后面的章节中会大量的用到.很简单的调用一个方法而已.join() : 等待线程的终止
1.8.守护线程的创建和运行
嗯!这段的描述,让我疑惑了.准备写点demo验证下.守护线程(daemon) : 这种线程的优先级很低,通常来说一个程序中没有其他线程运行的时候,守护线程才运行.当守护线程是程序中唯一的线程的时候,守护线程结束后,jvm也就结束了.
因为这种特性,守护线程通常用来作为统一程序中普通线程(也称为用户线程)的服务提供者.它通常是无线循环的,以等待服务请求或则执行线程的任务.因此他们不能做重要的工作,因为不知道守护线程什么时候能获取cpu时钟指令,也有可能随时结束.
好把.我的疑问:
优先级低,不知道何时能获取cpu始终指令我能理解,但是说 一个程序中没有其他线程运行的时候,守护线程才运行? 是什么意思
* 总结 *
作为守护线程的 线程,要在该线程start前设置.
守护线程 会一直在后台运行,如果没有任何用户线程运行的时候,守护线程也会 结束.
isDaemon() : 获取是否是守护线程
示例
场景描述: 下面的示例 ,就是 用3个线程 来往队列中增加元素. 用一个守护线程来清除元素./** * Created by zhuqiang on 2015/10/12 0012. */ public class Client { public static void main(String[] args) { LinkedBlockingQueue<Event> clq = new LinkedBlockingQueue<Event>(); // Deque<Event> deque = new ArrayDeque<>(); for (int i = 0; i < 3; i++) { new AddTask(i + ":name", clq).start(); } CleanTask cleanTask = new CleanTask(clq); cleanTask.setDaemon(true); //要在 任务开始前设置守护线程 cleanTask.start(); } } class AddTask extends Thread { private String name; //任务名称 // private Deque<Event> dq; //队列,该线程任务将 每秒往队列中增加一个元素 private LinkedBlockingQueue<Event> clq; public AddTask(String name, LinkedBlockingQueue<Event> clq) { this.name = name; this.clq = clq; } @Override public void run() { for (int i = 0; i < 10; i++) { clq.add(new Event(name + ":" + i, new Date())); System.out.println(Thread.currentThread().getName() + " : 增加了元素 size:" + clq.size()); try { TimeUnit.SECONDS.sleep(1); // TimeUnit.MILLISECONDS.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } } // 清除线程,一直运行 class CleanTask extends Thread { // private Deque<Event> dq; private LinkedBlockingQueue<Event> clq; public CleanTask(LinkedBlockingQueue<Event> clq) { this.clq = clq; } @Override public void run() { while (true) { long time; Date now = new Date(); Event last = null; try { last = clq.take(); } catch (InterruptedException e) { e.printStackTrace(); } Date date = last.getDate(); time = now.getTime() - date.getTime(); System.out.println("清除了一个元素:" + JSON.toJSONString(last) + " dq.size=" + clq.size()); // System.out.println("清除线程 运行中 ************" + dq.size()); } } } class Event { private String name; //事件名称 private Date date; //创建时间 public Event(String name, Date date) { this.name = name; this.date = date; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
* 一部分运行结果 *
Thread-0 : 增加了元素 size:1 Thread-1 : 增加了元素 size:2 Thread-2 : 增加了元素 size:3 清除了一个元素:{"date":1444663754124,"name":"0:name:0"} dq.size=2 清除了一个元素:{"date":1444663754125,"name":"1:name:0"} dq.size=1 清除了一个元素:{"date":1444663754125,"name":"2:name:0"} dq.size=0 Thread-0 : 增加了元素 size:2 Thread-1 : 增加了元素 size:3 Thread-2 : 增加了元素 size:2 清除了一个元素:{"date":1444663755126,"name":"2:name:1"} dq.size=2 清除了一个元素:{"date":1444663755126,"name":"0:name:1"} dq.size=1 清除了一个元素:{"date":1444663755126,"name":"1:name:1"} dq.size=0 Thread-1 : 增加了元素 size:2 Thread-2 : 增加了元素 size:3
* 结果说明 *
我最开始按照书上的例子,使用ArrayDeque来作为存储元素的队列,最后发现守护线程获取到的大小一直是0,然后我把守护线程休眠,就能获取到非0的队列. 这个就是一个线程问题了. 所以我觉得书上的列子是错误的结论. 然后使用 线程安全的队列(就是上面的示例),也只证实了.守护线程 会随着没有用户线程的时候跟着消失! 不知道是不是我的机器性能太好的缘故.书上的例子 没有办法重现证书说的是正确的.
1.9.线程中不可空异常的处理
Java中分为两种异常:非运行时异常(Checked Exception):这种异常必须在方法声明throws语句.或则在方法体中捕获
运行时异常(Unchecket Exception): 这种感异常 不必抛出,也可以捕获.
在run方法中,不支持抛出异常.所以 如果出现了在运行时异常,你不捕获(一般不仔细看api是不会知道的).默认是在控制台打印. 好在java提供了另一种在线程中捕获运行时异常的一种机制.
implements Thread.UncaughtExceptionHandler 类
在线程start前设置异常处理器 thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler);
这种捕获异常的方法.只可能是 运行时异常.原理肯定是 try 了下,然后把线程对象和异常对象回调给处理器的.( 不过短时间没有找到相关的源码)
也可以使用静态方法 Thread.setDefaultUncaughtExceptionHandler(new MyExHander()); 设置异常处理器
jvm调用查找异常处理器的顺序: 线程对象设置的 –> 线程组(ThreadGroup的) –> 最后是上面讲的默认的异常处理器
示例
/** * Created by zhuqiang on 2015/10/14 0014. */ public class Client { public static void main(String[] args) { Thread thread = new Thread(new Task()); thread.setUncaughtExceptionHandler(new MyExHander()); //设置自定义的 异常处理器 thread.start(); } } //异常处理器 class MyExHander implements Thread.UncaughtExceptionHandler{ @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName()); System.out.printf("Exception:%s,msg=%s",e.getClass().getName(),e.getMessage()); } } class Task implements Runnable{ @Override public void run() { int sss = Integer.parseInt("sss"); // 运行时异常 } }
* 运行结果 *
Thread-0 Exception:java.lang.NumberFormatException,msg=For input string: "sss"
1.10.线程局部变量的使用
在一个task被多个线程运行的时候,那么这个task中的属性就成了共享属性,但是有时候,我们并不想变量被所有线程共享,这个时候 就要用到 线程局部变量(Thread-Local Variable)机制了.很简单的使用,就不示例了.伪代码,把loc 用ThreadLocal来包装,并初始化. 而不是使用private Date date;
ThreadLocal<Date> loc = new ThreadLocal<Date>(){ @Override protected Date initialValue() { return new Date(); } }; Date date = loc.get(); //获取值 System.out.println("开始时间:" + date); loc.set(new Date()); //设置值 System.out.println("结束时间:" + loc.get()); loc.remove(); //删除值
InheritableThreadLocal : 也是一种局部变量,不过它是用于给子线程 获取父线程的 局部变量的.假如:A线程创建了B线程.线程B的局部变量和A的局部变量是一样的.也可以覆盖childValue()方法,这个方法用来初始化子线程在线程局部变量中的值.它使用父线程在线程局部变量中的值作为参数传入.
1.11.线程的分组
好吧,这个我觉得是一个很有趣的功能.之前一直都没有学习过.ThreadGroup(线程组): 表示一组线程,可以包含线程对象,也可以包含线程组对象,它是一个树形结构.
在某些情况下,线程分组比较好控制,比如在多个线程运行中,你要控制他们.只需要一个单一的操作就能达到效果.
好把.看示例和运行结果,原来线程分组就是这样使用的.但是在以下的示例中,其实有弊端的.前面已经讲到过了, 中断:当线程在活动之前或活动期间处于正在等待、休眠或占用状态且该线程被中断时,抛出该异常InterruptedException .这样不在这些状态的时候 就没招了.然而不是还有一种方法么 就是通过检测是否中断
if (Thread.interrupted()) // Clears interrupted status! throw new InterruptedException();
前面也有讲到,那么在下面的示例中 其实就很难运用到线程分组用组来操作线程了. 其他的我也没有想通.
示例
场景描述: 将创建几个线程,并把他们分到一组.只要有一个线程找到了指定的数字,就让其他几个线程中断./** * Created by zhuqiang on 2015/10/14 0014. */ public class Client { public static void main(String[] args) throws InterruptedException { ThreadGroup group = new ThreadGroup("xxx"); for (int i = 0; i < 10; i++) { Thread t = new Thread(group, new Task(2,group)); t.start(); // TimeUnit.MILLISECONDS.sleep(200); } int i = group.activeCount(); System.out.println("活动的线程:" + i); System.out.println("打印线程组信息---- 开始"); group.list(); System.out.println("打印线程组信息---- 结束"); Thread[] list = new Thread[i]; group.enumerate(list); //把活动的线程复制到指定的线程中. for (Thread t : list) { System.out.printf("name=%s,state=%s\n", t.getName(),t.getState());; } } } class Task implements Runnable{ private int num; private ThreadGroup xx; public Task(int num, ThreadGroup xx) { this.num = num; this.xx = xx; } @Override public void run() { try { System.out.println(Thread.currentThread().getName() + " : start"); TimeUnit.MILLISECONDS.sleep((long) (Math.random() * 1000)); Random random = new Random(); int i = random.nextInt(3); if(i== num){ System.out.println(Thread.currentThread().getName() + " : 命中目标"); xx.interrupt(); //找到了就中断所有线程组中的线程 } System.out.println(Thread.currentThread().getName() + " : end"); }catch (InterruptedException e){ return; //直接返回 } } }
* 某一次运行结果 *
活动的线程:10 打印线程组信息---- 开始 java.lang.ThreadGroup[name=xxx,maxpri=10] Thread[Thread-0,5,xxx] Thread[Thread-1,5,xxx] Thread[Thread-2,5,xxx] Thread[Thread-3,5,xxx] Thread[Thread-4,5,xxx] Thread[Thread-5,5,xxx] Thread[Thread-6,5,xxx] Thread[Thread-7,5,xxx] Thread[Thread-8,5,xxx] Thread[Thread-9,5,xxx] 打印线程组信息---- 结束 name=Thread-0,state=RUNNABLE Thread-7 : start Thread-6 : start Thread-3 : start Thread-2 : start Thread-9 : start Thread-8 : start Thread-5 : start Thread-4 : start Thread-1 : start Thread-0 : start name=Thread-1,state=BLOCKED name=Thread-2,state=RUNNABLE name=Thread-3,state=RUNNABLE name=Thread-4,state=RUNNABLE name=Thread-5,state=RUNNABLE name=Thread-6,state=RUNNABLE name=Thread-7,state=RUNNABLE name=Thread-8,state=RUNNABLE name=Thread-9,state=TIMED_WAITING Thread-9 : end Thread-0 : 命中目标 Thread-0 : end
1.12.线程组中不可空异常的处理
直接上代码,全是干货extends ThreadGroup
重写 uncaughtException(Thread t, Throwable e) 方法.只要该线程组中有抛出异常的,该方法就会被调用
/** * Created by zhuqiang on 2015/10/14 0014. */ public class Client { public static void main(String[] args) { MyGroup my = new MyGroup("my"); for (int i = 0; i < 3; i++) { new Thread(my,new Task()).start(); } } } //线程组,覆盖uncaughtException方法,捕获 当前组中所有抛出的非捕获异常 class MyGroup extends ThreadGroup{ public MyGroup(String name) { super(name); } @Override public void uncaughtException(Thread t, Throwable e) { System.out.printf("%s,Exception:%s,msg=%s\n",t.getName(),e.getClass().getName(), e.getMessage()); } } class Task implements Runnable{ @Override public void run() { Integer.parseInt("ss"); } }
* 运行结果 *
Thread-1,Exception:java.lang.NumberFormatException,msg=For input string: "ss" Thread-2,Exception:java.lang.NumberFormatException,msg=For input string: "ss" Thread-0,Exception:java.lang.NumberFormatException,msg=For input string: "ss"
1.13.使用工厂类创建线程
这个就不讲了.很简单的. 在 7.4.实现ThreadFactory接口生成定制线程 已经使用过了./** * Created by zhuqiang on 2015/10/14 0014. */ public class Client { public static void main(String[] args) { MyFactrory myFactrory = new MyFactrory(); Thread thread = myFactrory.newThread(new Runnable() { //用我们的工厂来创建 线程 @Override public void run() { } }); } } class MyFactrory implements ThreadFactory{ @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setPriority(2); // 可以设置优先级 thread.setName("xxxxxx" + (long)(Math.random() * 10) ); // 可以设置线程名称等 return thread; } }
相关文章推荐
- 新手学Struts2的几个小注意事项
- spring学习日记(day1)
- 【华为OJ】201301 JAVA 题目0-1级
- spring整合消息队列rabbitmq
- 动态执行的方法java
- Java反射
- null pointer at org.springframework.beans.PropertyEditorRegistrySupport
- 给出 《java学习笔记》 PDF格式
- 黑马程序员一一高级开发工具Eclipse
- Spring 容器初始化方法
- java缓存技术
- java判断一个字符串是否为空的方法总结
- 学习心得(Java语言)
- Java从入门到精通14-GridLayout网格布局
- springMVC的HandlerInterceptor拦截器
- 关于java中有符号数转换成无符号数的相关问题
- Java从入门到精通13-FlowLayout布局
- 抽象工厂模式(java语言实现)
- 《深入理解java虚拟机》之内存模型与安全
- Java内存泄露监控工具__JVM监控工具介绍