DougLea 并发设计大师
单核到多核,达到并行计算,线程是轻量级,成本低,效率高 合理利用多核cpu资源,提升对计算机资源的利用
线程合理利用cpu资源,提高程序的吞吐量 比较多的实际是线程池,一般不会new一个线程来使用,线程有风险 使用new Thread造成资源不可控
如何去应用线程池? 对账,通过线程进行跑批 BIO模型优化
如何改造程序实现异步化处理?
生命周期 线程共有六种状态 线程使用目的,提高程序的性能
java中的线程状态 6种 线程启动,终止 interrupt
锁(保护线程安全) synchonic 修饰方法,修饰代码块,修饰实例 以上方法锁的范围不同。作用范围不同,锁的范围由对象生命周期决定的 锁的范围,为什么锁的范围会有影响, 互斥锁的本质:共享资源
锁,对象锁 这是jvm源码,这里保存对象头 下面这个就是对象头 轻量级锁,重量级锁,偏向锁, 加锁会带来性能开销, 偏向锁,轻量级锁,重量级锁
锁的升级
jdk1.6之前是加重量级锁,会导致性能下降,之后又优化,这里涉及锁的升级。这个是由jvm层面实现的,我们不用管。 针对不同情况进行优化,提高效率。
首先偏向锁,没有获取就会升级到轻量级锁,然后重量级锁,阻塞线程 所以优化就是,在线程阻塞前,抢占锁,轻量级或者偏向锁 让线程不阻塞,也可以抢占到锁。在不加锁情况解决线程安全问题
偏向锁(默认关闭,线程没有竞争时候提升性能,真是情况没有必要开启偏向锁,所以一般就是无锁,轻量级锁,重量级锁) 首先访问同步代码块,看对象头中是有存储了线程id,(上面对象头表中有)如果没有存储,会通过cas操作(CAS,乐观锁,保证原子性,比较并替换,比较预期数据和原始内存中数据是否一致)将其替换掉。当前线程会存储标记,这是在没有竞争的情况下,用偏向锁 如上图 1表示偏向锁,01表示锁的标记,ThreadId会有值。下图总共32位
如果现在有另一个线程访问,cas操作会失败,会撤销原来获得的偏向锁,暂停原来的线程,解锁,将对象头中的线程id设置为空,恢复到无锁状态,恢复线程。 如果原来线程正在运行,无法撤销,会升级锁为轻量级锁,然后以轻量级锁竞争锁对象
线程栈有Lock record,对象头Object复制到其中,owner指向锁对象 轻量级锁,栈中存储对象头,通过cas操作,指向占中的指针。当线程2进入,失败,重试机制,自旋锁,多次cas操作(线程获得锁和释放锁时间短),但是也不能一直重试,自适应自旋,会根据上一次抢占时间长短觉定这一次时间多少(底层实现),相比于线程阻塞,挂起的性能好,所以用自旋。如果在指定自旋(自适应自旋)此时还没有获得锁,自旋失败,修改为重量级锁,没有获得锁的线程阻塞,等待唤醒
重量级锁,队列中排队被阻塞的线程。 唤醒,进行新一轮的抢占
非公平锁,允许插队,syncholized
如何优化,存在竞争就会升级到重量级锁
生产者和消费者。两个不同的线程 线程通信(wait/notify)等待唤醒 wait作用,释放当前同步锁,实现线程阻塞 notify 唤醒被阻塞