1.线程状态变迁
2.为什么notify/notifyAll/ wait要在同步方法或块中执行
2.1在Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity。所有对象的非同步方法都能够在任意时刻被任意线程调用,此时不需要考虑加锁的问题。而对于对象的同步方法来说,在任意时刻有且仅有一个拥有该对象独占锁的线程能够调用它们。
2.2wait/notify/notifyAll作用
(1)当一个线程正在某一个对象的同步方法中运行时调用了这个对象的wait()方法,那么这个线程将释放该对象的独占锁并被放入这个对象的等待队列。注意,wait()方法强制当前线程释放对象锁。
(2)当某线程调用某对象的notify()或notifyAll()方法时,任意一个(对于notify())或者所有(对于notifyAll())在该对象的等待队列中的线程,将被转移到该对象的入口队列。接着这些队列(译者注:可能只有一个)将竞争该对象的锁,最终获得锁的线程继续执行。如果没有线程在该对象的等待队列中等待获得锁,那么notify()和notifyAll()将不起任何作用。在调用对象的notify()和notifyAll()方法之前,调用线程必须已经得到该对象的锁。
参考:https://www.cnblogs.com/xiohao/p/7118102.html
3.Thread方法(yield/join/sleep/守护线程)
yield:暂停当前正在执行的线程对象,只会给相同或更高高优先级执行,如果没有,则自己继续执行
join:a中调用b.join(),表示等b执行完才执行a;调用join前需调用start,使线程处于就绪状态
守护线程:a中有线程b启动,b设置守护为true,则b守护a,a结束后b也结束
4.多线程实现
4.1方式
(1)实现接口Runnable
(2)继承Thread
(3)Callable与FutureTask包装器实现
(4)线程池创建
参考:https://blog.csdn.net/java_zyq/article/details/87917734
4.2区别
* 如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大?
* 1. call()可以有返回值的。
* 2. call()可以抛出异常,被外面的操作捕获,获取异常的信息
* 3. Callable是支持泛型的
5.线程池
线程池接口介绍:https://blog.csdn.net/tongdanping/article/details/79604637
5.1自定义线程池
ThreadPoolExecutor类
【参数】
corePoolSize:线程池核心数大小
maximumPoolSize:最大可创建线程数
keepAliveTime:超过核心数时起作用(当核心与最大线程数一样时,该值无用)
unit:时间单位
workQueue:存储等待完成的任务
threadFactory:创建线程(执行命令的线程工厂)
handler:拒绝处理任务的策略(可以对丢弃的任务进行记录)----https://blog.csdn.net/jgteng/article/details/54411423
【线程池中线程初始化:0;1;all】prestartAllCoreThreads()方法---预创建worker线程
【任务拒绝策略:】
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。(默认)
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
【线程池关闭:】
shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
【几种线程池区别:】
Executors.newFixedThreadPool(int); //定长
new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
Executors.newSingleThreadExecutor(); //可设置,默认大小:Integer.MAX_VALUE
new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
Executors.newCachedThreadPool(); //定长:1
new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
newScheduledThreadPool;//定长,周期,定时
【如何合理配置线程池大小:】
如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 NCPU+1
如果是IO密集型任务,参考值可以设置为2*NCPU
【基本方法】
1)submit的效果和execute是一样的,只是execute没有返回值,而submit有返回值。
2)线程池可以执行(callable与runnable线程)
3)invokeAny、invokeAll
invokeAny取得第一个方法的返回值,当第一个任务结束后,会调用interrupt方法中断其它任务。
invokeAll等线程任务执行完毕后,取得全部任务的结果值。
【周期执行任务线程】
以newScheduledThreadPool为例:
scheduleAtFixedRate:以上一个任务开始时间计时,120秒过去后,上一个任务是否执行完,如果执行完毕,则当前任务立即执行,如果上一个任务未执行完,则需等上一个任务执行完后立即执行。直至追上次数后,再周期执行。
scheduleWithFixedDelay:以上一个任务结束时开始计时,120秒过去后,立即执行。
【补充】
* 1.使用executors创建线程池,不推荐使用,建议使用ThreadPoolExecutor自定义构建
* 2.线程池可执行callable线程/线程集合,有返回值;thread可执行callable;
* 3.手动定义线程池(核心线程池数量a,最大线程池数量b,延迟消亡线程时间c,时间单位d,请求阻塞队列e,创建work线程工厂f,自定义拒绝策略g)
(1)自定义work工厂:
(2)自定义拒绝策略:
(3)线程变迁过程:逐个创建线程f,达到a后,仍有线程进入,放入e,e满后,查看线程数是否达到b,如果达到,后续任务根据g。如果有线程空闲c时间后,如果当前线程数大于a,则该线程销毁。参考:https://blog.csdn.net/qq_37980436/article/details/105070229?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-3.channel_param
*4.线程间通信方式:参考:https://www.jianshu.com/p/5834de0897d9