深圳本地做网站,移动手机网站开发,深圳企业建站模板,申请个人网站和企业官网有什么不同JAVA的内存区域
程序计数器#xff1a;线程私有的#xff0c;保存当前线程的字节码文件。JAVA虚拟机栈#xff1a;包含局部变量信息#xff0c;用于方法的调用和执行。本地方法栈#xff1a;与JAVA虚拟机栈类似#xff0c;但只服务于本地方法。堆#xff1a;所有线程共…JAVA的内存区域
程序计数器线程私有的保存当前线程的字节码文件。JAVA虚拟机栈包含局部变量信息用于方法的调用和执行。本地方法栈与JAVA虚拟机栈类似但只服务于本地方法。堆所有线程共享存放对象实例变量GC的主要区域。方法区所有线程共享用于存放已经被JVM加载的类信息。运行时常量池所有线程共享方法区的一部分存储编译期间生成的字面量和符号引用
JAVA栈和堆的区别
栈主要用于存储局部变量和方法调用的上下文信息栈中数据生命周期短暂当元素调用结束时占空间会被释放每个线程有自己独立的栈空间栈上的数据不能被其他线程访问和修改堆栈上的数据访问速度更快堆中数据涉及复杂的算法保证数据分配和回收。堆主要用于存储对象实例和变量堆的生命周期不稳定当对象不再被引用时堆会自动调用GC进行回收堆中的数据所有线程共享可以被其他线程访问和修改。
JAVA虚拟机栈溢出情况
递归调用过深当一个方法调用自身时如果没有正确的终止条件或者终止条件不满足。方法调用层次过深层层嵌套调用。线程过多栈帧过大方法中局部变量过多或者单个局部变量过大JVM参数配置不当JVM为每个线程分配的栈过小。
解决方法
优化递归逻辑确保递归调用有明确的终止条件如果可以将递归改为迭代。合理设置JVM参数增加每个线程的大小。避免无限制创建线程。
垃圾回收GC算法
Serial单线程在回收垃圾的时候会暂停所有的事情。CMS多线程采用标记-清理方法产生大量空间碎片。G1多线程强化分区将JVM堆划分为多个区域每次选择最多的区域进行回收。
类加载器
类加载器是JVM加载类文件的组件它负责将字节码文件加载到内存中并转化为.class对象。
类加载过程
加载根据类的全限定名查找它的字节码文件并创建.class对象验证验证类文件格式是否正确准备为静态变量创建内存并初始化默认值解析将符号引用改为直接引用初始化之形类的静态初始化块以及对静态变量赋值
分类
启动类加载器、扩展类加载器和应用程序类加载器
双亲委派模型
当一个类加载器需要加载一个类的时候它先让它的父类去加载这个类如果父类无法加载它就自己加载这主要是为了避免核心类库被重复加载。
进程和线程
进程资源分配的基本单位拥有独立的内存空间和资源创建和销毁开销大具有良好的错误隔离和稳定性。线程程序执行的基本单位共享进程的内存资源适合高效的并发和并行程序。并发一个系统能够处理多个任务这些任务不需要同时执行并行同一时刻执行多个任务
用户线程执行具体的业务逻辑完成程序的核心功能。只要有一个用户线程在执行JVM就不会退出。
守护线程提供辅助功能主要用于后台任务它的生命周期取决于用户线程一旦用户线程执行完毕JVM会强制退出所有的守护线程也会退出。
Start和Run方法
Start会创建并执行一个新的线程Run只是执行当前线程不会启动一个新线程。
线程状态
new线程刚创建时候就绪在可运行线程池中等待CPU时间片运行获得CPU时间片开始运行阻塞等待某种条件的发生等待锁的释放终止线程执行完毕
Sleep和Wait
Sleep是线程类的方法它不会释放锁而是在指定时间后恢复对线程的执行用于定时任务或者防止循环过快消耗CPU资源。Wait是Object类的方法它会释放锁然后等待另一个线程用notify来唤醒用于线程间的同步和通信。
锁
公平锁保证线程按照它们申请的顺序获得锁每个线程都会获得锁不会导致线程饥饿。
非公平锁不保证线程按照它们申请的顺序获得锁锁的获取和释放更快但可能导致线程饥饿。
Sychronized锁
JAVA的关键字用于线程之间互斥和同步作用于方法和代码块由JVM管理简单易用可重入自动释放锁它是自动释放锁可能会导致线程饥饿不可中断。保证互斥、原子性和可见性。
Sychronized锁升级
偏向锁优化技术减少无竞争情况下的同步代价。如果一个线程获得了偏向锁它在接下来的的锁请求中无需进行同步操作直接进入临界区。只有在其他线程尝试竞争这把锁的时候偏向锁才会撤销锁的头部会记录第一个获得锁线程的ID当这个锁再次被线程请求的时候无需CAS直接进入临界区。适合于无竞争情况减少无竞争下的同步开销。轻量级锁自旋锁线程获取锁失败的时候不立即阻塞而是忙循环反复尝试获取锁。适合于竞争时间比较小的锁避免线程阻塞和唤醒的开销。锁粗化将多个小范围锁合并成一个大范围的锁减少加锁解锁的开销。锁去除在编译期间判断锁对象是否只在当前线程内使用如果是则去除锁。
首先Sychronized通过尝试获取偏向锁来竞争资源如果能竞争到代表加锁成功如果不行则需要将锁升级为轻量级锁在轻量级锁状态下线程会根据自旋次数来抢占锁资源如果还是无法竞争到会升级到重量级锁在重量级锁状态下没有竞争到锁的线程会被阻塞。
Volatile
轻量级的同步机制保证变量的可见性和有序性它通过将修改后的值直接刷新到内存中来确保其他线程对修改后的变量值立即可见通过禁止指令重排序来达到有序性。
Lock
Lock最常用的实现类是Reentrantlock可重入锁允许一个线程多次获取同一个锁而不会阻塞。它的锁的获取和释放需要显示调用lock()和unlock()方法它可以被配置为公平锁或者非公平锁提供了trylock()方法来中断锁提供了更加强大的功能是用于处理复杂场景。
Sychronized与Volatile区别
Volatile比Sychronized有更小的性能开销但Volatile只保证可见性和有序性不保证复杂操作的原子性它只适合状态标志、配置参数等不涉及复杂逻辑的变量在复杂场景下仍旧使用Sychronized。
Sychronized与Lock区别
Sychronized是JAVA关键字Lock是JUC的接口Lock的灵活性更高它可以使用lock()和unlock()方法随时加锁、解锁Sychronized只能在同步代码块执行完自动释放锁Lock提供了非公平锁和公平锁Sychronized只提供非公平锁如果同步代码块中抛出异常Sychronized会自动释放Lock则需要在finally中显示释放否则会导致死锁。总之Sychronized提供了更加简单直接的同步机制而Lock提供了功能更加强大更灵活的同步机制。
Threadlock
Threadlock是线程变量为每个使用该变量的线程提供了一个变量副本每个线程可以独立修改自己的变量副本而不受其他线程的影响。它的实现核心在于每个线程维护了一个ThreadlockMap的对象该对象保存了自己的本地变量。
使用场景
线程的上下文切换数据库连接事务管理事务处理中保存每个事务信息对象跨层传递时打破层级间的约束避免多次传递
可能会导致内存泄漏因为ThreadlockMap键是弱引用但是它的值是强引用。当Threadlock没有被其他引用时它会被GC收回但是它的值无法回收。每次使用Threadlock后要利用remove清除数据。
JAVA内存模型
可见性线程对变量的修改对其他线程可见原子性操作是不可以分割的要么完全成功要么失败有序性禁止指令重排序工作内存和主内存主内存是线程共享区域工作内存是每个线程私有区域。工作内存中保留了线程所需要的变量副本线程修改变量的时候是在工作内存中修改完成后刷新到主内存中。
JAVA内存模型中的关键机制
Volatile可见性和有序性Sychroized互斥、可见性、有序性和原子性happens-before保证前一个操作在后一个操作之前且对后一个操作可见。
JAVA中常见的并发容器
ConcurrentHashMap采用分段锁的技术将整个数据分为多个段每个段使用独立锁在JAVA 8以后采用更加高效CAS和同步链表代替分段锁进一步提高性能。CopyonWriteArraylist写操作时不直接修改原来的数组而是创建一个新的数组使用新数组来代替就数组在读多写少的情况下性能更高。
线程池
线程启动前就创建若干个线程等待响应减少了频繁创建和销毁线程的开销通过控制并发线程数量和合理的任务调度来更好地进行资源调度避免在高并发下因为创建过多线程导致系统崩溃提供了更好的系统稳定性在完成任务后将线程归还到池中避免线程未正确销毁导致的泄露。
线程池的参数
核心线程数线程池中始终保持的线程数量线程池会优先使用核心线程来执行任务最大线程数线程池中可以创建线程的上限空闲线程存活时间非核心线程在执行完任务后最久存活时间任务队列存储等待执行的线程当前线程数达到核心线程的数量时新提交的任务会保留在任务队列中拒绝策略当任务队列已满且达到最大线程数时线程池无法接受新的任务
实现原理
线程池在创建时根据默认的参数配置核心线程无论是否当前有任务需要执行这些线程都会一直保留在线程池中。当需要执行任务时线程池会优先使用这些线程去执行。如果当前没有空闲的核心线程就会把这个任务放在任务队列中等待执行。如果任务队列已满但还未达到线程池中所能接受的最大核心数时线程池会创建一个新的线程去处理这个任务。当任务队列已满且线程数达到最大线程数时线程池采用拒绝策略停止继续工作。任务完成后线程会返回空闲状态。核心线程不会回收非核心线程会根据空闲线程存活时间进行回收。当线程池不在需要的时候调用shutdown()和shutdownnow()来执行shutdown()是等待已提交的任务完成后回收shutdownnow()会尝试停止当前正在执行的任务然后回收
线程池的拒绝策略
默认策略直接抛出异常调用者运行策略提交任务的线程自己处理任务降低任务提交速度直接丢弃策略丢弃无法处理的任务不抛出异常丢弃最旧策略丢弃队列中最旧的未处理的任务
execute和submit区别
execute只能提交实现了Runnable接口的任务不返回任何结果当出现异常时会直接抛出异常。submit可以提交实现了Runnable和Callable接口的任务对于Callable任务会返回一个Future对象这个对象可以检查任务是否完成如果遇到异常允许调用者捕获并处理异常。