JUC学习笔记(下篇)

目录

一、ThreadLocal

1、简介

2、Thread、ThreadLocal、ThreadLocalMap的关系

3、ThreadLocal存在的内存泄漏问题

 4、总结

二 、java对象内存布局和对象头

 1、简介

 2、对象头

 3、实例数据和对齐填充

4、对象分代年龄

 5、压缩指针说明

三、Synchronized与锁升级

1、前言

2、无锁

 3、偏向锁

3.1、 理论

3.2、 案例

3.4、使用jvm参数来控制是否开启偏向锁

 3.5、偏向锁的撤销(升级为轻量级锁)

4、轻量级锁

 5、加锁后hascode的存储

6、总结

四、AQS

五、读写锁

 1、ReentrantReadWriteLock

2、StampedLock(邮戳锁或票据锁)


一、ThreadLocal

1、简介

 helloWorld

class House{
    //初始化为零
    ThreadLocal<Integer> saleCount = ThreadLocal.withInitial(()->0);

    void saleHouse(){
        saleCount.set(1 + saleCount.get());
    }
}
public class Demo9 {
    public static void main(String[] args) {
        House house = new House();
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        try {
            for (int i = 0; i< 5; i++){
                executorService.submit(()->{
                    int i1 = new Random().nextInt(5)+1;
                    try {
                        for (int j = 0; j < i1; j++){
                            house.saleHouse();
                        }
                        System.out.println(Thread.currentThread().getName() + "\t" + house.saleCount.get());
                    }finally {
                        house.saleCount.remove();
                    }
                });
            }
        }finally {
            executorService.shutdown();
        }
    }

2、Thread、ThreadLocal、ThreadLocalMap的关系

3、ThreadLocal存在的内存泄漏问题

 

 为什么Entry是弱引用ThreadLocal的

 清除脏Entry、

 4、总结

 

二 、java对象内存布局和对象头

 1、简介

 2、对象头

2.1、对象标记Mark Word

如果开启了压缩指针,那么类指针可能为4字节

 

2.2、类元信息(又叫类型指针)

 3、实例数据和对齐填充

 

4、对象分代年龄

 5、压缩指针说明

压缩指针是默认开启de

三、Synchronized与锁升级

1、前言

在jdk1.6以前锁操作是面向操作系统的重量级操作,假如锁的竞争比较激烈的话,性能下降

 

从java6开始优化Synchronized,引入了轻量级锁和偏向锁,使锁有一个升级的过程

2、无锁

 3、偏向锁

在jdk15后将逐步淘汰偏向锁,但现在公司大部分使用的jdk8

3.1、 理论

3.2、 案例

3.4、使用jvm参数来控制是否开启偏向锁

默认有4秒的延时

 3.5、偏向锁的撤销(升级为轻量级锁)

4、轻量级锁

存在多线程竞争,但是任意时刻,只有一个锁在竞争,不存在锁竞争的太过激烈的情况,也就没有线程阻塞

 

 自旋的程度

 5、加锁后hascode的存储

 

6、总结

锁消除

每个线程进入这个方法都会new 一把锁,用的不是同一把锁

 锁粗化

四、AQS

Juc24_AQS的概述、体系架构、深入源码解读(非公平)、源码总结_所得皆惊喜的博客-CSDN博客

五、读写锁

 1、ReentrantReadWriteLock

 

 锁降级

2、StampedLock(邮戳锁或票据锁)

Stamp:代表了锁的状态,当stamp返回零是,表示获取锁失败,并且,当释放锁或者转换锁的时候要获取的stamp的值

1、锁饥饿问题

2、出现的原因

 3、特点

 4、缺点

5、案例

package com.bilibili.juc.rwlock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * @auther zzyy
 *
 * StampedLock = ReentrantReadWriteLock + 读的过程中也允许获取写锁介入
 */
public class StampedLockDemo
{
    static int number = 37;
    static StampedLock stampedLock = new StampedLock();

    public void write()
    {
        long stamp = stampedLock.writeLock();
        System.out.println(Thread.currentThread().getName()+"\t"+"写线程准备修改");
        try
        {
            number = number + 13;
        }finally {
            stampedLock.unlockWrite(stamp);
        }
        System.out.println(Thread.currentThread().getName()+"\t"+"写线程结束修改");
    }

    //悲观读,读没有完成时候写锁无法获得锁
    public void read()
    {
        long stamp = stampedLock.readLock();
        System.out.println(Thread.currentThread().getName()+"\t"+" come in readlock code block,4 seconds continue...");
        for (int i = 0; i < 4; i++) {
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(Thread.currentThread().getName()+"\t"+" 正在读取中......");
        }

        try
        {
            int result = number;
            System.out.println(Thread.currentThread().getName()+"\t"+" 获得成员变量值result:"+result);
            System.out.println("写线程没有修改成功,读锁时候写锁无法介入,传统的读写互斥");
        }finally {
            stampedLock.unlockRead(stamp);
        }
    }

    //乐观读,读的过程中也允许获取写锁介入
    public void tryOptimisticRead()
    {
        long stamp = stampedLock.tryOptimisticRead();
        int result = number;
        //故意间隔4秒钟,很乐观认为读取中没有其它线程修改过number值,具体靠判断
        System.out.println("4秒前stampedLock.validate方法值(true无修改,false有修改)"+"\t"+stampedLock.validate(stamp));
        for (int i = 0; i < 4; i++) {
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(Thread.currentThread().getName()+"\t"+"正在读取... "+i+" 秒" +
                    "后stampedLock.validate方法值(true无修改,false有修改)"+"\t"+stampedLock.validate(stamp));
        }
        if(!stampedLock.validate(stamp))
        {
            System.out.println("有人修改过------有写操作");
            stamp = stampedLock.readLock();
            try
            {
                System.out.println("从乐观读 升级为 悲观读");
                result = number;
                System.out.println("重新悲观读后result:"+result);
            }finally {
                stampedLock.unlockRead(stamp);
            }
        }
        System.out.println(Thread.currentThread().getName()+"\t"+" finally value: "+result);
    }


    public static void main(String[] args)
    {
        StampedLockDemo resource = new StampedLockDemo();

        /*传统版
        new Thread(() -> {
            resource.read();
        },"readThread").start();

        //暂停几秒钟线程
        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"\t"+"----come in");
            resource.write();
        },"writeThread").start();

        //暂停几秒钟线程
        try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); }

        System.out.println(Thread.currentThread().getName()+"\t"+"number:" +number);*/

        new Thread(() -> {
            resource.tryOptimisticRead();
        },"readThread").start();

        //暂停2秒钟线程,读过程可以写介入,演示
        //try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }

        //暂停6秒钟线程
        try { TimeUnit.SECONDS.sleep(6); } catch (InterruptedException e) { e.printStackTrace(); }

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"\t"+"----come in");
            resource.write();
        },"writeThread").start();


    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值