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();
}
}
来源:CSDN
作者:limeOracle
链接:https://blog.csdn.net/limeOracle/article/details/104277589