
2022-02-01
338
原创
synchronized 、Lock 、线程池
synchronized 和 Lock 有什么区别?
- 原始结构
- synchronized 是关键字属于 JVM 层面,反应在字节码上是 monitorenter 和 monitorexit,其底层是通过 monitor 对象来完成,其实 wait/notify 等方法也是依赖 monitor 对象只有在同步快或方法中才能调用 wait/notify 等方法。
- Lock 是具体*(java.util.concurrent.locks.Lock)是 api 层面的锁。
- 使用方法
- synchronized 不需要用户手动去释放锁,当 synchronized 代码执行完后系统会自动让线程释放对锁的占用。
- ReentrantLock 则需要用户手动的释放锁,若没有主动释放锁,可能导致出现死锁的现象,lock() 和 unlock() 方法需要配合 try/finally 语句来完成。
- 等待是否可中断
- synchronized 不可中断,除非抛出异常或者正常运行完成。
- ReentrantLock 可中断,设置超时方法 tryLock(long timeout, TimeUnit unit),lockInterruptibly() 放代码块中,调用 interrupt() 方法可中断。
- 加锁是否公平
- synchronized 非公平锁
- ReentrantLock 默认非公平锁,构造方法中可以传入 boolean 值,true 为公平锁,false 为非公平锁。
- 锁可以绑定多个 Condition
- synchronized 没有 Condition。
- ReentrantLock 用来实现分组唤醒需要唤醒的线程们,可以精确唤醒,而不是像 synchronized 要么随机唤醒一个线程要么唤醒全部线程。
线程池使用过吗?谈谈对 ThreadPoolExector 的理解?
为什使用线程池,线程池的优势?
线程池用于多线程处理中,它可以根据系统的情况,可以有效控制线程执行的数量,优化运行效果。线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,那么超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。
主要特点为:
- 线程复用
- 控制最大并发数量
- 管理线程
主要优点;
- 降低资源消耗,通过重复利用已创建的线程来降低线程创建和销毁造成的消耗。
- 提高相应速度,当任务到达时,任务可以不需要的等到线程创建就能立即执行。
- 提高线程的可管理性,线程是稀缺资源,如果无限制的创建,不仅仅会消耗系统资源,还会降低体统的稳定性,使用线程可以进行统一分配,调优和监控。
线程池的几个重要参数
- corePoolSize -核心线程池大小
- maximumPoolSize - 最大线程池大小
- keepAliveTime - 线程池中超过 corePoolSize 数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true) 使得核心线程有效时间
- TimeUnit - keepAliveTime 时间单位
- workQueue - 阻塞任务队列
- threadFactory - 新建线程工厂
- RejectedExecutionHandler - 当提交任务数超过 maxmumPoolSize+workQueue 之和时,任务会交给RejectedExecutionHandler 来处理
线程池的拒绝策略
- 是什么
- 等待队列已经满了,再也塞不下新的任务,同时线程池中的线程数达到了最大线程数,无法继续为新任务服务。
- 拒绝策略
- AbortPolicy:处理程序遭到拒绝将抛出运行时 RejectedExecutionException
- CallerRunsPolicy:线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
- DiscardPolicy:不能执行的任务将被删除
- DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)
多线程