• 多线程之享元模式和final原理


    1 享元模式

    1 定义

    享元模式,Flyweight pattern, 当需要重用数量有限的同一类对象时使用.

    2 体现

    1 包装类

    Jdk中Boolean, Byte, Short, Integer, Long, Character等包装类提供了valueOf方法.以Long的valueOf为例, 会缓存-128到127之间的Long对象,在此区间会重用对象,大于这个范围才会新建Long对象.

        public static Long valueOf(long l) {
            final int offset = 128;
            if (l >= -128 && l <= 127) { // will cache
                return LongCache.cache[(int)l + offset];
            }
            return new Long(l);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Byte,Short, Long缓存的范围都是-128到127

    Character缓存的范围是0-127

    Integer的默认范围是-128到127, 最小值不能变,最大值可以通过调整虚拟机参数-Djava.lang.Integer.IntegerCache.high来改变

    Boolean缓存了TRUE和FALSE

    2 BigDecimal类

        private static BigDecimal add(BigInteger fst, int scale1, BigInteger snd, int scale2) {
            int rscale = scale1;
            long sdiff = (long)rscale - scale2;
            if (sdiff != 0) {
                if (sdiff < 0) {
                    int raise = checkScale(fst,-sdiff);
                    rscale = scale2;
                    fst = bigMultiplyPowerTen(fst,raise);
                } else {
                    int raise = checkScale(snd,sdiff);
                    snd = bigMultiplyPowerTen(snd,raise);
                }
            }
            BigInteger sum = fst.add(snd);
            return (fst.signum == snd.signum) ?
                    new BigDecimal(sum, INFLATED, rscale, 0) :
                    valueOf(sum, rscale, 0);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    单个方法是采用保护性拷贝类方式, 是原子的,线程安全的, 但是不能保证多个方法的组合是原子的,线程安全的,所以在使用中,需要其他方法保证,如使用AtomicReference.

    2 final原理

    1 设置final的原理

    根据之前volatile原理,对比final的实现.

    public class TestFinal {
     final int a = 20;
    }
    
    • 1
    • 2
    • 3

    对应字节码文件:

    0: aload_0
    1: invokespecial #1 // Method java/lang/Object."":()V
    4: aload_0
    5: bipush 20
    7: putfield #2 // Field a:I
     <-- 添加了写屏障
    10: return
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    发现 final 变量的赋值也会通过 putfield 指令来完成,同样在这条指令之后也会加入写屏障,保证在其它线程读到 它的值时不会出现为 0 的情况

    2 获取final的原理

    public class TestFinal {
     final int A = 20;
     final int B = Short.MAX_VALUE + 1;
        
     static final int a = 20;
     static final int b = Short.MAX_VALUE + 1; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    根据编译的字节码文件可知, 当数据较小就在栈内存中获取,数据量超过最大,就在类常量池中.

    3 无状态

    在 web 中,设计 Servlet 时为了保证其线程安全,都会有这样的建议,不要为 Servlet 设置成员变量,这种没有任何成员变量的类是线程安全的

    因为成员变量保存的数据也可以称为状态信息,因此没有成员变量就称之为【无状态】

  • 相关阅读:
    Hive特殊函数的使用
    JavaScript基础
    力扣labuladong一刷day2共7题
    机器学习工作岗位
    MySQL锁
    C语言- 数据转换汇总
    主流开发环境和开发语言介绍
    Blob和ArrayBuffer和File
    常微分方程算法之编程示例六-解一阶方程组(龙格-库塔法)
    MySQL(2)
  • 原文地址:https://blog.csdn.net/ABestRookie/article/details/126236630