java知识点汇总
基础篇
线程安全
-
说说线程安全问题
计算机系统资源分配的单位为进程,同一个进程中允许多个线程并发执行,并且多个线程 会共享进程范围内的资源:例如内存地址。当多个线程并发访问同一个内存地址并且内存 地址保存的值是可变的时候可能会发生线程安全问题,因此需要内存数据共享机制来保证 线程安全问题 是否多线程访问可变的共享变量 发挥多处理器的强大能力,提高效率和程序的吞吐量 -
volatile 实现原理
volatile修饰变量就是告知程序任何对该变量的访问都需要从共享内存中获取 而对他的改变必须同步刷新回共享内存,保证所有线程对变量访问的可见性 -
synchronize 实现原理
由monitorenter指令进入,然后monitorexit释放锁,在执行monitorenter之前 需要尝试获取锁,如果这个对象没有被锁定,或者当前线程已经拥有了这个对象的锁, 那么就把锁的计数器加1。当执行monitorexit指令时,锁的计数器也会减1 偏向锁:锁不存在线程竞争 轻量锁:两个线程申请一个锁对象 重量级锁:同一时间多个线程竞争锁 -
synchronized 与 lock 的区别
synchronized:普通方法锁的是实例对象,静态同步方法锁的是当前的class对象 同步代码块锁的是括号中的对象 前者是java的关键字,后者是一个类 前者以获取锁的线程执行完同步代码块,释放锁,线程执行异常,jvm会让线程释放锁 后者在finally中必须释放锁,不然易造成死锁 前者锁状态无法判断,后者可以判断 前者可重入不可中断非公平,后者可重入可判断可公平 前者适用少量同步,后者适用大量同步 lock:一般使用ReentrantLock类作为锁,加锁和解锁需要使用lock和unlock来显示指出 所以一般会在finally中加unlock来防止死锁 -
CAS 乐观锁
synchronized是一种独占锁,会导致其他所有未持有锁的线程阻塞,而等待持有锁的线程释放锁 乐观锁就是每次不加锁而是假设没有冲突而去完成某项操作,如果冲突失败就重试,直到成功为止 采用的机制就是cas 原子操作类,concurrent.atomic包下的包装类,AtomicBoolean,AtomicInteger,AtomicLong cas机制中使用了三个基本操作数:内存地址V,旧的预期值A,要修改的新值B 更新一个变量的时候,只有当变量的预期值A和内存地址V中的实际值相同时,才会将内存地址中的V 修改为B cas缺点:并发量高的情况下,如果许多线程反复尝试更新某个变量却一直不成功,会给cpu带来很大压力 保证的只是单个变量的原子性操作,而非整个代码块 -
ABA 问题
当一个值从A更新成B,又更新回A,普通CAS机制会误判通过检测 利用版本号比较可以有效解决ABA问题 例如AtomicStampedReference类 -
乐观锁的业务场景及实现方式
每次获取数据的时候都不会担心数据被修改,所以每次获取数据的时候都不会进行加锁,但是在更新数据的 时候需要判断该数据是否被别人修改过,如果被其他线程修改则不进行数据更新,如果没被其他线程修改过 则进行数据更新,由于数据没有加锁,期间该数据可以被其他线程进行读写操作 比较适合读取操作比较频繁的场景,如果出现大量写操作,数据发生冲突的可能性会增大,为了保证数据 的一致性,应用层需要不断获取数据这样会增加大量查询操作,降低系统的吞吐量