对笔者近期刚阅读完的Thinking In Java的12.2节简单作个概述:java
本节的主要内容:编程
Runnable
接口、Callable
接口以及继承 Thread
类,而且各自实现的优点Executor
(线程执行器),简要介绍了 CachedThreadPoo
l、SingleThreadPool
以及 FixedThreadPool
三种基本的线程执行器Runnable
接口(无返回值的任务描述)以及 Callable
接口(有返回值的任务描述)Thread
对象的 基本操做方式: Thread t
=> t.yield()
t.start()
t.sleep()
t.join()
t.wait()
t.interrupt
( join
, wait
和interrupt
笔者没有书写特定的示例,在下方的博客资料中有详细的更优秀的博客作了相关方面的描述)run()
方法中逃逸的异常(在Main线程中没法try/catch到的)如下是笔者的笔记,对于Java中的进程的基本概念有不少知识还须要参考操做系统(如:线程的三种基本态:执行态、等待态、执行态以及补充的挂起态和激活态)。大部分笔者本身的理解都放在了代码中,若是有疏漏的还期望dalao们私聊指点下笔者(小萌新一只)!缓存
package cnboy.henu.xb; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; /** * Thinking In Java 21.2 基本的线程进制 学习的样例代码 * @author Administrator * * 最重要要理清概念 “线程”与“任务”,任务须要线程的驱动,Runnable以及Callable接口所作的事情是描述一个任务,而Thread则是开启一个线程,附着在任务上,驱动任务的执行 */ public class ExcutorTry { public static void main(String[] args) { // TODO Auto-generated method stub // // 执行器对象 提供中间层管理任务对象(线程) // /** // * 下面是使用的SingleTheadPool作的示例 // */ // ExecutorService exec1 = Executors.newSingleThreadExecutor(); // // 此对象缓存的线程对象仅只有一个,所以其它须要执行的任务会自动排队等待执行 // for(int i=0;i<10;i++) { // exec1.execute(new TaskWithoutResult(i)); // } // exec1.shutdown(); // /** // * 下面是利用的 CachedThreadPool 作的示例 // */ // ExecutorService exec = Executors.newCachedThreadPool(); // // Future对象正如名字所示,能够表明一个异步任务返回的对象并提供获取其值的方式 // List<Future<String>> results = new ArrayList<Future<String>>(); // for(int i=0;i<10;i++) { // results.add(exec.submit(new TaskWithResult(i))); // } // // 关闭执行器,不让新的任务添加进来 // exec.shutdown(); // for(Future<String> fs:results) { // try { // // 判断fs是否已经执行完毕,也能够不加,不加的状况下会自动阻塞等待其执行完毕 // if(fs.isDone()) { // System.out.println(fs.get()); // } // }catch(InterruptedException e){ // e.printStackTrace(); // } catch (ExecutionException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } // // 这里执行描述的任务的Runner其实是Main线程而不是launch对象 LiffOff launch = new LiffOff(10);launch.run(); Thread.yield(); // // 这里执行描述的任务对象是线程 t ,此处才是真正的多线程并发执行(main 线程以及 t 线程) // Thread t = new Thread(new LiffOff(10)); // t.start();System.out.println("Waiting for Liff Out!"); // // 这里模仿了6个线程并发的执行状况(main + 五个new Thread) // for(int i=0;i<5;i++) { // new Thread(new LiffOff(10)).start(); // } /** * Daemon线程 (守护线程,定义为DaemonThread意味着此线程不属于程序中不可或缺的一部分,常见的 GC线程是Daemon线程) * Daemon进程fork出来的子线程也会被自动设置为Daemon线程 */ // // 将线程执行器设置为后台线程执行器(即建立执行任务的线程都是后台线程),采用构造注入的方式将后台线程Factory注入执行器中 // ExecutorService daemonExec = Executors.newCachedThreadPool(new DaemonThreadFactory()); // for(int i =0;i<5;i++) { // // 后台执行 // daemonExec.execute(new TaskWithoutResult(i)); // } // daemonExec.shutdown(); // System.out.println("All Daemon Thread Started!"); // try { // // 等待一下Daemon 线程的执行(有趣的是能够调节等待时间观察Daemon线程执行与非后台线程执行的关系,即非后台线程执行完毕,Daemon线程也会同时退出) // //TimeUnit.SECONDS.sleep(10);// 后台线程执行完毕 // TimeUnit.MICROSECONDS.sleep(1000);// 后台线程来不及执行完毕 // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } /** * 使用继承Thread类的方式实现多线程,缺点在于没法再继承其余类,而实现Runnable接口任然能够继承其余类 */ // for(int i=0;i<5;i++) { // new SimpleThread(); // } /** * 一般咱们在run()里出现的异常(从线程中逃逸,向父线程传播)若是不加以特殊处理(如使用UncaughtExceptionHandle),而只是简单的在Main里经过try/catch是没办法捕获并处理异常的 * 所以咱们须要引入UncaughtExceptionHandle为咱们的线程加上一道安全防线(使用在ThreadFactory、Executor) * */ // ExecutorService exceptionExec = // Executors.newCachedThreadPool(new HandleThreadFactory()); // exceptionExec.execute(new ExceptionThread()); // exceptionExec.shutdown(); } } /** * 不带返回值的任务 * @author Administrator * */ class TaskWithoutResult implements Runnable{ private int id; public TaskWithoutResult(int id) { // TODO Auto-generated constructor stub this.id = id; System.out.println("Generate Runnable Task : id = "+id); } @Override public void run() { // TODO Auto-generated method stub System.out.println(String.format("Task Without Result => id = %d", id)); } } /** * 带返回值的任务 实现的Callable接口 * @author Administrator * */ class TaskWithResult implements Callable<String>{ private int id=0; public TaskWithResult(int id) { // TODO Auto-generated constructor stub this.id = id; } /** * 注意不是Run方法 */ @Override public String call() throws Exception { // TODO Auto-generated method stub // 模仿下有任务的线程 return String.format("ask With Result => id = %d", id); } } /** * 这个任务描述是模拟的火箭发射的例子 * @author Administrator * */ class LiffOff implements Runnable{ protected int countDown =10; private static int taskCount = 0; private final int id=taskCount++; public LiffOff(int countDown) { // TODO Auto-generated constructor stub this.countDown = countDown; } public String Status() { return String.format("# %d (", id)+(countDown>0?countDown:"Liff Off!")+")"; } @Override public void run() { // 模拟火箭发射倒计时 while(countDown-- >0) { System.out.println(Status()); // 让步 告诉线程调度器此线程核心工做已完成,能够进行上下文切换了 /** * 与sleep不一样的是,sleep是让线程进入阻塞态,这时不管比线程高优先级仍是低优先级的线程均可以被执行 * 而yeild仅仅只是让出此时间片,进入可执行态也就是它并不会等待一次完整的轮转后再之执行,而是有可能随时又进入执行态(可能刚yeild完毕又被调用了),所以它只能让步与它同优先级或者是高优先级的线程 */ //Thread.yield(); /** * 换成sleep,能够看到每一个线程都会按照时间轮转进行输出,而不是抢占的输出(会按照顺序输出) */ try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /** * 专门用于建立后台进程的ThreadFactory * @author Administrator * */ class DaemonThreadFactory implements ThreadFactory{ @Override public Thread newThread(Runnable r) { // TODO Auto-generated method stub Thread t = new Thread(r); // 这里设置线程为后台线程 t.setDaemon(true); return t; } } /** * 模拟一种实现线程的方式:继承自Thread类 * @author Administrator * */ class SimpleThread extends Thread{ protected int countDown =5; private static int taskCount = 0; public SimpleThread() { // TODO Auto-generated constructor stub // 经过调用父类的构造函数,给线程名字赋值 super(Integer.toString(taskCount++)); // 在构造函数中便启动线程 -- 不推荐的方式,仅为了方便作示例 start(); } @Override public String toString() { // TODO Auto-generated method stub return "#"+getName()+"("+countDown+")"; } @Override public void run() { // TODO Auto-generated method stub while(true) { System.out.println(this); if(countDown-- ==0) { return; } } } } /** * 模拟一个在run()方法中抛出异常的Runnable对象 * @author Administrator * */ class ExceptionThread implements Runnable{ @Override public void run() { // TODO Auto-generated method stub // 模拟执行过程当中抛出异常 Thread t = Thread.currentThread(); System.out.println("run() by "+ t); System.out.println("eh = "+t.getUncaughtExceptionHandler()); throw new RuntimeException(); } } /** * 模拟一个用以处理逃逸的异常的UncaughtExceptionHandler对象 * @author Administrator * */ class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{ /** * uncaughtException方法会在线程因未捕获的异常而面临死亡的时候被调用 */ @Override public void uncaughtException(Thread t, Throwable e) { // TODO Auto-generated method stub System.out.println("caught :"+e); } } /** * 模拟的一个为线程设置异常处理的ThreadFactory * @author Administrator * */ class HandleThreadFactory implements ThreadFactory{ @Override public Thread newThread(Runnable r) { // TODO Auto-generated method stub // 记录建立线程的过程 System.out.println(this+"\tcreating new Thread"); Thread t = new Thread(r); System.out.println("created \t" + t); // 给与线程UncaughtException处理器 t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); System.out.println("eh = "+t.getUncaughtExceptionHandler()); return t; } }
附:学习中借鉴的几篇优秀的博客安全