Think In Java 21.2.14 捕获异常

夙愿已清 提交于 2020-02-12 14:24:01
package lime.tij._021._002._014;

import java.util.concurrent.*;

/**
 * @Author : Liangmy
 * @Description :
 * @Date : Created in 2020/2/6 下午1:58
 * @Modified By :
 * 
 *  *  01. 任务
 *      Thread.yield() : 1. 仅使当前线程从运行状态转到可运行状态,而不是等待或阻塞状态。
 *      Thread.yield() : 2. 将当前线程的运行机会交给线程池中拥有相同优先级的线程。
 *      Thread.yield() : 3. 并不能一定保证当前线程由运行状态转到可运行状态。
 *      Runnable::run() : 当从Runnable导出一个类时,它必须具有run()方法,但是这个run()不会产生任何内在的线程能力。要实现线程行为,你必须显式地将一个任务附着到线程上。
 *  02. 线程
 *      将Runnable对象转变为工作任务的传统方式是把它提交给一个Thread构造器
 *      调用Thread对象的start()方法为该线程执行必需的初始化操作,然后调用Runnable的run()方法,以便在这个新线程中启动该任务。
 *  03. 线程池
 *      Java SE5的java.util.concurrent包中的执行器(Executor)将为你管理Thread对象,从而简化了并发编程。
 *      Executor在客户端和任务执行之间提供了一个间接层;与客户端直接执行任务不同,这个中介对象将执行任务。
 *      Executor允许你管理异步任务的执行,而无须显示地管理线程的生命周期
 *      ???异步任务的执行???
 *      ???线程的生命周期???
 *      我们可以使用Executor来代替在MoreBasicThreads.java中显示地创建Thread对象。LiftOff对象知道如何运行具体的任务,与命令模式一样,它暴露了要执行的单一方法。
 *      ExecutorService(具有服务生命周期的Executor,例如关闭)知道如何构建恰当的上下文来执行Runnable对象。
 *      shutdown方法的调用可以防止新任务被提交给这个Executor,当前线程(在本例中,即驱动main()的线程)将继续运行在shutdown()被调用之前提交的所有任务。这个程序将在Executor中的所有任务完成之后尽快退出。
 *      newCachedThreadPool : 使用无限的线程集来执行所提交的任务(return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());)
 *      newFixedThreadPool : 使用有限的线程集来执行所提交的任务(return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());)
 *      在任何线程池中,现有线程在可能的情况下,都会被自动复用。
 *      CachedThreadPool在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程。
 *  04. 从任务中产生返回值
 *      Callabel是一种具有类型参数的泛型,它的类型参数表示的是从方法call()中返回的值,并且必须使用ExecutorService.submit()方法调用它。
 *  05. 休眠
 *      sleep()使任务中止执行给定的时间。
 *      sleep()可以抛出InterruptedException异常,它在run()中被捕获,因为异常不能跨线程传播会main(),所以必须在本地处理所有在任务内部产生的异常。
 *      TimeUnit.MICROSECONDS.sleep(timeout);
 *      由于操作系统之间的差异性,你不能依赖sleep()来规定线程之间的顺序行为,最好使用同步控制,或者在某些情况下,自己编写协作例程,这些例程将会按照指定的顺序在互相之间传递控制权。
 *  06. 优先级
 *      JDK有10个优先级,但是它与多数操作系统都不能很好的匹配。
 *      唯一可移植的方法是当调整优先级的时候,只使用MAX_PRIORITY、MAX_PRIORITY和MIN_PRIORITY三种级别。
 *  07. 让步
 *      Thread.yield()仅仅是一种暗示,并没有任何机制保证它将会被采纳,而且只是建议具有相同优先级的其他线程可以运行。
 *      LiftOff.java使用yield()在各种不同的LiftOff任务之间产生分布良好的处理机制。
 *  08. 后台进程
 *      setDaemon()
 *      是指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。
 *      因此,当所有的非后台线程结束时,程序也就终止了。同时会杀死进程中的所有后台线程。
 *      反过来说,只要有任何非后台线程还在运行,程序就不会终止。
 *      必须在线程启动之前调用setDaemons()方法,才能把它设置为后台线程。
 *      ThreadFactory(interface)
 *      通过编写定制的ThreadFactory可以定制有Executor创建的线程的属性(后台、优先级、名称)
 *      每个静态的ExecutorService创建方法都被重载为接受一个ThreadFactory对象,而这个对象将被用来创建新的线程:
 *          public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
 *              return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),threadFactory);
 *          }
 *      isDeamon()方法确定线程是否是一个后台线程。
 *      如果是一个后台线程,那么它创建的任何线程将被自动设置成后台线程。
 *      后台进程在不执行finally子句的情况下就会终止其run()方法。
 *  09. 编码的变体 1.直接继承Thread 2. 自管理的Runnable 3. 内部类隐藏线程代码 3.1 内部类继承Thread 3.2 内部匿名类Thread 3.3 内部类实现Runnable,自管理的Runnable 3.4 内部匿名类Runnable 3.5 使用指定的方法启动线程
 *      在非常简单的情况下,你可能会希望使用直接冲Thread继承这种可替代的方式。
 *      可以调用Thread构造器为Thread对象赋予具体的名称,这个名称可以通过getName()获得。
 *      实现接口使得你可以继承另一个不同的类,而从Thread继承将不能继承另一个不同的类。
 *      在构造器中启动线程,另一个任务可能会在构造器结束之前开始执行,这意味这该任务能够访问处于不稳定状态的对象。这是优选Executor而不是显示地创建Thread对象的另一个原因。
 *  10. 术语 线程、任务
 *      Thread类自身不执行任何操作,它只是驱动赋予它的任务。
 *      任务:描述将要执行的工作
 *      线程:驱动任务的具体机制
 *  11. 加入一个线程 join()
 *      一个线程可以在其他线程之上调用join()方法,其效果是等待一段时间直到第二个线程结束才继续执行。
 *      如果某个线程在另一个线程t上调用t.join(),此线程将被挂起,直到目标线程t结束才恢复(即t.isAlive()返回为假)
 *      也可以在调用join()时带上一个超时参数(单位可以是毫秒,或者毫秒和纳秒),这样如果目标线程在这段时间到期时还没有结束的话,join()方法总能返回。
 *      对join()方法的调用可以被中断,做法是在调用线程上调用interrupt()方法,这时需要用到try-catch子句。
 *      当另一个线程在该线程上调用interrupt()时,将给该线程设定一个标志,表明该线程已经被中断。然而,异常被捕获时将清理这个标志,所以在catch子句中,在异常被捕获的时候这个标志总是为假。
 *  12. 创建有响应的用户界面
 *
 *  13. 线程组
 *      线程组持有一个线程集合。
 *  14. 捕获异常
 *      由于线程的本质特性,使得你不能捕获从线程中逃逸的异常。
 *      一旦异常逃出任务的run()方法,他就会向外传播到控制台。
 *      将main的主体放到try-catch语句块中也时没有用的。
 *      如何解决"未捕获的异常"这个问题?
 *      修改Executor产生线程的方式。Thread.UncaughtExceptionHandler允许您在每个Thread对象上都附着一个异常处理器。
 *      Thread.UncaughtExceptionHandler.uncaughtException()会在线程因未捕获的异常而临近死亡时被调用。
 *  15.
 *  16.
 *  17.
 *  18.
 *  19.
 *
 *
 */
class ExceptionThread2_2 implements Runnable {

    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run() by " + t);
        System.out.println("eh = " + t.getUncaughtExceptionHandler());
        throw new RuntimeException();
    }
}

class MyUncaughtExceptionHandler_2 implements Thread.UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("caught " + e);
    }
}

class HandlerThreadFactory_2 implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        System.out.println(this + " creating new Thread");
        Thread t = new Thread(r);
        System.out.println("created " + t);
        t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler_2());
        System.out.println("eh = " + t.getUncaughtExceptionHandler());
        return t;
    }
}

public class CaptureUncaughtException_2 {
    public static void main(String[] args) {
//        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler_2());
//        ExecutorService executorService = Executors.newCachedThreadPool();
        ExecutorService executorService = Executors.newCachedThreadPool(new HandlerThreadFactory_2());
        // submit 和 execute 什么区别?前者没有调用Thread.UncaughtExceptionHandler.uncaughtException(),后者调用了。
        // ExecutorService中submit和execute的区别
        // 1、接收的参数不一样
        // 2、submit有返回值,而execute没有
        // 3、submit方便Exception处理
        // submit()能在返回的Future对象调用get()方法的时候再次抛出线程中的异常,而execute()会交由线程的UncaughtExceptionHandler去处理。

        executorService.execute(new ExceptionThread2_2());
//        Future<?> submit = executorService.submit(new ExceptionThread2_2());
//        try {
//            submit.get();
//        } catch (InterruptedException e) {
//            System.out.println("1");
//            e.printStackTrace();
//        } catch (ExecutionException e) {
//            System.out.println("2");
//            e.printStackTrace();
//        }
        executorService.shutdown();
    }
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!