高并发多线程笔记

本文深入探讨了Java并发编程的关键概念,包括CAS算法及其ABA问题解决方案,synchronized的锁状态升级过程,volatile确保线程可见性但不保证原子性,以及ThreadLocal在多线程中的应用。同时,提到了内存屏障和CPU指令重排序对并发的影响,以及不同类型的引用类型如强引用、软引用和弱引用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、CAS算法     无锁优化  自旋锁

  CompareAndSwap  比较和交换

AtomicInteger i = new AtmoicInteger();
i.incrementAndGet();//自增并返回结果

//incrementAndGet() 方法跟踪进去会发现底层是调用的native方法 ( Unsafe.class类中的 
//public final native boolean compareAndSwapInt(...)  )
//最终执行的就是linux底层的一条汇编指令  lock cmpxchg 指令

//synchronized 和 volatile 最终底层都是使用 lock cmpxchg 指令

  

 ABA问题:线程1读取了数据0做++,回来校验原值时,这个过程中,其他线程对数据0做了修改,只是最终结果又变成了0,即原值为A,过程中被改为了B,最终又被改为了A,就是ABA问题。

解决办法:数据0加上版本号,每个线程读取数据0时连同版本号一起读取, 每次处理完回来比较的时候连同版本号一起比较即可。   AtomicStampedReference 可带版本

2、sychronized    与   对象在内存中的布局息息相关

   

 

  

2.1、锁的4种状态及升级过程

   new(无锁状态)----->  偏向锁(第一次上锁)-----> 轻量锁(有人竞争时) -----> 重量锁(竞争激烈时)

   下图 为锁的布局信息,markword共64位,8个字节,都在markword里

     

2.2、sychronized的执行过程;

      a.编码阶段:java代码:sychronized关键字

      b.编译阶段:class文件:moniterenter------->moniterexit

      c.运行阶段:执行过程种锁自动升级

      d.底层实现:lock comxchg

 

3、volatile 

3.1、线程可见性(,无法保证原子性,无法替代synchronized)

     MESI 缓存一致性协议

    不通型号的cpu的每个缓存行大小不通,如 X86 是 32BYTES ,而 ALPHA 是 64个字节,

    这里面有缓存行对齐的概念,即,让一个变量始终独占一个缓存行,处理这个变量的线程在修改主内存里的这个变量时,不需要通知其他线程来同步这个变量;当使用volatile关键字修饰时,多线程下对性能有很大的提高,典型案例  Disruptor  开源的并发框架   

3.2、禁止cpu指令重排序   

      DCL单例     Double Check Lock

cpu的乱序执行(重排序),cpu先后接收互不影响的指令1和指令2,指令1执行很慢,这时在等待指令1返回结果的时候,cpu把指令2执行完了,这种情况就是cpu的乱序执行,单线程下没问题,多线程下会有问题。

 

3.2.1、jvm内存屏障

    jvm的内存屏障两边的指令不可以重排序,保证指令的有序性;

    Load读,Store写

    

volatile关键字解决cpu指令重排序的方式:   

代码层面使用volatile关键字修饰,编译后的字节码文件也只是增加了volatile关键字,加载到jvm时,jvm根据其自身的规范,在看到volatile关键字时,开始添加内存屏障,使用两个内存屏障把volatile修饰的操作隔离起来,上屏障之前的指令都做完,才能执行volatile操作,volatile操作执行完,才能执行下屏障后面的指令 ,这样就是实现了禁止指令重排序(乱序执行)

     

 4、ThreadLocal

 4.1、java对象与引用类型   强 软 弱  虚

    强类型:普通引用类型

    软引用: 用于缓存管理,空间不够用的时候就会被自动回收

                    java.lang.ref.SoftReference<byte[]> sr = new SoftReference<>(new byte[1024*1024*10]);

    弱引用:管理一次性的对象,一旦遇到垃圾回收,就会被回收掉

           ThreadLocal:  线程本地对象,每个线程独自拥有,其内部的东西(对象、数据、连接等)其他线程不可见,线程存在,ThreadLocal对象就一直存在

           Spring中@Transactional注解就是使用ThreadLocal实现的事务管理,当一个方法m()使用@Transactional注解修饰,其内部又调用了m1()和m2()两个方法,这两个方法都要连接数据库,只有m1和m2使用的是同一个数据库连接时,才能保证事务,此处数据库连接就是放在ThreadLocal中的。

public class ThreadLocalDemo {

    static ThreadLocal<Person> tl = new ThreadLocal<>();

    public static void main(String[] args) {

        new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(tl.get());
        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            tl.set(new Person());
        }).start();
    }

    static class Person{
        String name = "zhangsan";

    }
}

      WeakReference

/**
 * 弱引用类型------一次性的对象场景
 * @author zxj
 * @date 2020/5/11 8:39
 */
public class _WeakReference {
    public static void main(String[] args) {

        WeakReference<M> m = new WeakReference<>(new M());

        System.out.println(m.get());
        System.gc();
        System.out.println(m.get());

        ThreadLocal<M> t1 = new ThreadLocal<>();
        t1.set(new M());//  追踪源码
        t1.remove(); //当set进去的数据无用时,必须手动清理set进去的数据,否则底层的map由于key时弱引用,遇到gc就被回收了,但是map里的value还存在,不手动清理,会造成内存泄漏
    }
}

 t1.set()源码

map.set()源码

new Entry()源码

 

 

    虚引用:管理堆外内存的

/**
 * 虚引用类型 ---- 管理堆外内存 off heap
 * @author zxj
 * @date 2020/5/11 8:43
 */
public class _PhantomReference {
    private static final List<Object> LIST = new LinkedList<>();
    private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
    public static void main(String[] args) {
        PhantomReference<M> phantomReference = new PhantomReference<>(new M(), QUEUE);

        new Thread(() -> {
            while(true){
                LIST.add(new byte[1024*1024]);
                try{
                    Thread.sleep(1000);

                }catch (InterruptedException e){
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
                System.out.println(phantomReference.get());
            }
        }).start();

        new Thread(() -> {
            while (true){
                Reference<? extends M> poll = QUEUE.poll();
                if(poll != null){
                    System.out.println("---虚引用对象被jvm回收了----" + poll);
                }
            }
        }).start();

        try {
            Thread.sleep(500);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

    零拷贝技术

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值