最近在学习并发这块,特此记录下
1.线程的创建有两种,一种是继承Thread,一种是实现Runnable
2.线程中止
1.一般执行完run 方法就会自然终止,或者抛出异常提前结束。
其中stop() 方法不建议使用,源码标记也是过期方法,因为此方法在终止线程的时候不会保证线程的资源正常释放,因此会导致程序可能工作在不确定的状态下。
2.中断 interrupt() 可以安全的中止,但是此方法并不是立马中止,而是相当于发出通知,A程序要中断了。同样,A程序完全可以不理会这个通知,仍然完成自己的工作,因为java的线程是协作式,而不是抢占式的,因此线程本身需要检查自身的中断标志是否被置为true 来进行响应。
线程可以通过isInterrupt() 来进行判断,也可以调用Thread.interrupt()。 不过Thread.interrupt()
会同时把中断标识改为false。
如果线程处于阻塞状态,(例如sleep,join,wait),线程在检查到中断标识为true 会抛异常InterruptedException,并会清除标识,重新设置为false。
不建议自定义标志位来中止线程。
注:处于死锁状态的线程无法被中断
3.run()和start()
start() 方法才是真正意义的启动线程,new Thread() 其实只是new 一个实例。因此star() 不可被重复调用,不然会出错。**run()**就是一个普通的方法,可以多次调用。也可以单独调用。
4.join()
把指定的线程加入当前的线程,可以将两个交替执行的线程合并为顺序执行,比如B线程中调用了A线程的join(),必须在A执行完后才回执行B线程。
5.synchronize
内置锁机制,核心是对象锁,锁住两个对象 可以并行,加了static 锁的是类。
6.volatile
只能保持可见性,不能保持原子性, 因此使用的场景:一写,多读。
7.ThreadLocal
ThreadLocal为每个线程都提供了变量的副本,使得每个线程在某个时刻访问的都并非同一个对象,这样就隔离了多个线程对数据的数据共享。
其中Spring的事务就借助了此类。
ThreadLocal 里 每个线程对应一个ThreadLocalMap 其中key就是Threadocal,value 就是需要隔离的变量,
这个map里面对应的Entry 。(待完,这块也是看的迷迷糊糊的,缕好在写下吧)
++++++++++++++++++++++++++++++++++++++分割线+++++++++++++++++++++++++++++++++++++++++++++++++
8. 线程池
使用线程池的原因:
·
- 降低资源消耗
- 提高响应速度
- 提高线程的管理性
ThreadPoolExecutor与Executor的关系
参数的意义
从上往下分别是
corePoolSize核心线程数,
maximumPoolSize最大线程数,
keepAliveTime空闲线程的存活时间,
TimeUnit时间单位,
workQueue阻塞队列:必须是有界的阻塞队列即BlockingQueue
threadFactory创建线程的工厂:通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名, 当然还可以更加自由的对线程做更多的设置, 比如设置所有的线程为守护线程。
RejectedExecutionHandler饱和策略:4种
(1) AbortPolicy: 直接抛出异常, 默认策略;
(2) CallerRunsPolicy: 用调用者所在的线程来执行任务;
(3) DiscardOldestPolicy: 丢弃阻塞队列中靠最前的任务, 并执行当前任务;
(4) DiscardPolicy: 直接丢弃任务;
也可以实现RejectedExecutionHandler接口自定义,比如记录日志持久化不能处理的任务。
线程池的工作机制
1.运行的线程少于corePoolSize时,直接创建线程执行(执行这部的时候需要获取全局锁)。
2.当线程数多余corePoolSize时,则将任务加入BlockingQueue。
3.当队列也满的时候,则创建新的线程来处理。数量小于maximumPoolSize。
4.如果maximumPoolSize也满了。则会执行所选的饱和策略。
扩展线程池
线程池中也有Spring 的 AOP使用相类似的操作。在任务执行前调用,执行后调用和退出时调用,只要重写beforeExecute,afterExecute和terminated方法。在shutdown后调用terminated。
提交任务
execute()方法用于提交不需要返回值的任务, 所以无法判断任务是否被线程
池执行成功。
submit()方法用于提交需要返回值的任务。 线程池会返回一个 future 类型的
对象, 通过这个 future 对象可以判断任务是否执行成功, 并且可以通过 future
的 get()方法来获取返回值, get()方法会阻塞当前线程直到任务完成, 而使用 get
(long timeout, TimeUnit unit) 方法则会阻塞当前线程一段时间后立即返回, 这
时候有可能任务没有执行完。
关闭线程池
shutdown和shutdownNow
前者是中断没有正在执行任务的线程,后者是直接中断所有的线程。原理就是和线程的中断一样逐个调用interrupt。
在调用isShutdown都会返回true,当所有的任务都已关闭后, 才表示线程池关闭成功, 这时调用 isTerminaed 方法会返回 true。
至于怎么使用这两个,看情况而定。
(先写这么多,好多东西要学习啊。。。。。。。。。。。。。。)