网站设计套餐,安卓和网站开发找工作,手机网站前端开发布局技巧,网站排名怎样做有效线程池
1 线程池的作用#xff1a;提高线程的利用率#xff0c;线程复用#xff0c;频繁的创建和销毁线程非常浪费资源
线程池的七大参数#xff1a; corePoolSize#xff08;核心线程数#xff09;#xff1a;线程池中始终保持的活动线程数#xff0c;即使它们处于空…线程池
1 线程池的作用提高线程的利用率线程复用频繁的创建和销毁线程非常浪费资源
线程池的七大参数 corePoolSize核心线程数线程池中始终保持的活动线程数即使它们处于空闲状态也不会被回收。 maximumPoolSize最大线程数线程池中允许存在的最大线程数。当工作队列满了且核心线程已经都在工作时线程池会创建新的线程但不会超过这个值。 keepAliveTime线程空闲时间当线程池中的线程数量超过核心线程数时多余的空闲线程在空闲时间达到一定值后会被终止。 unit线程空闲时间的单位用于指定keepAliveTime的时间单位例如秒、毫秒等。 workQueue工作队列用于存放等待执行的任务的队列可以是有界队列或无界队列如LinkedBlockingQueue、ArrayBlockingQueue等。 threadFactory线程工厂用于创建线程的工厂通常用来自定义线程的名称、优先级等。 handler拒绝策略当工作队列已满且线程池中的线程数量达到最大线程数时新任务的处理策略有四种常见的策略下文有详细介绍。
四种常见的拒绝策略 ThreadPoolExecutor.AbortPolicy默认策略当工作队列已满且线程池中的线程数量达到最大线程数时抛出RejectedExecutionException异常拒绝新任务的提交。 ThreadPoolExecutor.CallerRunsPolicy当工作队列已满时该策略会将任务返回给调用者即当前线程这样任务提交者将自己执行任务不会被丢弃。 ThreadPoolExecutor.DiscardOldestPolicy当工作队列已满时该策略将丢弃队列中最旧的任务即队列头部的任务然后尝试重新提交当前任务。 ThreadPoolExecutor.DiscardPolicy当工作队列已满时该策略会默默地丢弃新的任务不会抛出异常也不会执行任务
过程任务加入线程池后先判断核心线程数是否达到最大如果达到加入任务队列如果任务队列已满开启非核心线程如果达到最大线程数开始执行拒绝策略。
关闭线程池shutdown与shutdownnow的区别前者决绝任务的提交把之前任务队列中未完成的任务完成之后再关闭 后者直接关闭所有正在运行的任务。
如何设置最大线程数cpu密集型设置为cpu的核数Io密集型两倍cpu核数
为什么要自定义线程池参数
我们发现newFixedThreadPool和newSingleThreadExecutor方法他们都使用了LinkedBlockingQueue的任务队列LikedBlockingQueue的默认大小为Integer.MAX_VALUE。而newCachedThreadPool中定义的线程池大小为Integer.MAX_VALUE。
所以阿里禁止使用Executors创建线程池的原因就是FixedThreadPool和SingleThreadPool的请求队列长度为Integer.MAX_VALUE可能会堆积大量的请求从而导致OOM。
CachedThreadPool允许的创建线程数量为Integer.MAX_VALUE可能会创建大量的线程从而导致OOM。 synchronized
原理 synchronized 是 Java 中用于实现同步的关键字它的原理涉及到 Java 对象头和对象监视器的概念。以下是 synchronized 的基本原理 Java 对象头每个 Java 对象在内存中都有一个对象头其中包含了对象的元数据信息如哈希码、GC 分代信息等。这些元数据存储在对象头中占用一定的内存空间。 对象监视器MonitorJava 对象头中的一部分用于实现同步被称为对象监视器或锁。每个对象都有一个关联的对象监视器它用于控制对对象的并发访问。对象监视器可以被锁定locked和解锁unlocked。 Synchronized的语义底层是通过一个monitor监视器锁的对象来完成 每个对象有一个监视器锁(monitor)。每个Synchronized修饰过的代码当它的monitor被占用时就 会处于锁定状态并且尝试获取monitor的所有权 过程 1.如果monitor的进入数为0则该线程进入monitor然后将进入数设置为1该线程即为 monitor的所有者。 2.如果线程已经占有该monitor只是重新进入则进入monitor的进入数加1. 3.如果其他线程已经占用了monitor则该线程进入阻塞状态直到monitor的进入数为0再 重新尝试获取monitor的所有权。
特性
可重入性一个拿到锁的线程可以多次进入同步方法中比如在同步方法中调用另一个该锁对象的同步方法底层使用计数器实现1.如果monitor的进入数为0则该线程进入monitor然后将进入数设置为1该线程即为 monitor的所有者。 2.如果线程已经占有该monitor只是重新进入则进入monitor的进入数加1. 3.如果其他线程已经占用了monitor则该线程进入阻塞状态直到monitor的进入数为0再 重新尝试获取monitor的所有权。
不可中断性线程进入同步方法后其他线程只能阻塞等待不能中断拿到锁的进入同步方法里面的线程 synchronized 中四种锁的升级
在 Java 中synchronized 关键字支持多种不同的锁升级策略。这些策略使锁能够在多线程环境下有效地保护共享资源同时最大程度地减少线程间的竞争和锁的开销。 0 无状态锁没有任何线程进入同步代码块 偏向锁Biased Locking偏向锁是为了优化单线程场景而引入的。在单线程环境中无需进行复杂的竞争所以第一个获得锁的线程会获得偏向锁之后再次进入同步块时无需竞争直接获得锁。只有在有其他线程争用锁的情况下偏向锁才会升级为轻量级锁。 轻量级锁Lightweight Locking轻量级锁是为多线程场景优化的锁升级策略。当多个线程尝试争夺锁时JVM会将偏向锁升级为轻量级锁。轻量级锁使用 CAS 操作比较并交换来尝试获取锁而不是阻塞线程。如果获取锁的尝试成功那么线程可以快速进入临界区。如果失败轻量级锁会在达到一定的cas次数阈值之后升级为重量级锁它会升级为重量级锁。 重量级锁Heavyweight Locking重量级锁是最传统的锁升级策略当多个线程争夺锁时会导致其他线程阻塞直到获得锁的线程释放锁。这种锁升级策略涉及到操作系统层面的线程阻塞和唤醒因此性能开销相对较高。
synchronized 与Lock锁的区别
1 synchronized 是一个关键字Lock是一个接口
2 synchronized 是非公平锁Lock可以实现公平锁
3 synchronized 会自动释放锁Lock必须手动加锁与释放锁
4 在线程之间通信时synchronized 无法精准唤醒
5 lock锁更灵活的锁住代码
什么是自旋 很多 synchronized 里面的代码只是一些很简单的代码执行时间非常快此时等待的线程都加锁 可能是一种不太值得的操作因为线程阻塞涉及到用户态和内核态切换的问题。既然 synchronized 里面的代码执行得非常快不妨让等待锁的线程不要被阻塞而是在 synchronized 的边界做忙循环这就是自旋。如果做了多次循环发现还没有获得锁再阻塞这样可能是一种更 好的策略。
CAS
cas是unsafe包下的一个方法。基于乐观锁的实现机制。原理是内存值 预期值 新值如果内存值与预期值相等就把新值赋值给内存值否则失败。cas用于轻量级锁。
i的同步操作1 获取i的内存值 2 Ai1 3 iA
cas是实现第三步 cas导致的问题
1、ABA 问题 比如说一个线程 one 从内存位置 V 中取出 A这时候另一个线程 two 也从内存中取出 A并且 two 进行了一些操作变成了 B然后 two 又将 V 位置的数据变成 A这时候线程 one 进行 CAS 操作发现内存中仍然是 A然后 one 操作成功。尽管线程 one 的 CAS 操作成功但可能存在潜藏的问题。从Java1.5 开始 JDK 的 atomic包里提供了一个类 AtomicStampedReference 来解决 ABA 问题。问题取钱多按了几次取50的操作总共100第一次成功变为50如果有人转账给你50现在卡里有100第二次取钱操作也会执行成功变为50造成数据不一致问题 2、循环时间长开销大 对于资源竞争严重线程冲突严重的情况CAS 自旋的概率会比较大从而浪费更多的 CPU 资源效率低于 synchronized。 3、只能保证一个共享变量的原子操作 当对一个共享变量执行操作时我们可以使用循环 CAS 的方式来保证原子操作但是对多个共享变量操作时循环 CAS 就无法保证操作的原子性这个时候就可以用锁。 Volatile
可见性、有序性
ThreadLocal
ThreadLocal的使用_threadlocal如何使用-CSDN博客