欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

线程安全问题

程序员文章站 2022-05-04 10:09:46
...

线程安全问题线程安全问题
线程安全问题

线程安全问题

一、可见性、有序性

// 1、 jre/bin/server  放置hsdis动态链接库
//  测试代码 将运行模式设置为-server, 变成死循环   。 没加默认就是client模式,就是正常(可见性问题)
// 2、 通过设置JVM的参数,打印出jit编译的内容 (这里说的编译非class文件),通过可视化工具jitwatch进行查看
// -server -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation -XX:LogFile=jit.log
//  关闭jit优化-Djava.compiler=NONE
public class VisibilityDemo {
    private volatile boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        VisibilityDemo demo1 = new VisibilityDemo();
        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                // class ->  运行时jit编译  -> 汇编指令 -> 重排序, 热点代码重排序成 if((demo1.flag)){while(true){i++}}
                while (demo1.flag) { // 指令重排序
                   i++;
                }
                System.out.println(i);
            }
        });
        thread1.start();

        TimeUnit.SECONDS.sleep(2);
        // 设置is为false,使上面的线程结束while循环
        demo1.flag = false;
        System.out.println("被置为false了.");
    }
}

线程安全问题
线程安全问题线程安全问题
Java并发:volatile关键字详解

二、原子性

public class LockDemo1 {
    /*volatile*/ int value = 0;

    static Unsafe unsafe; // 直接操作内存,修改对象,数组内存....强大的API
    private static long valueOffset;

    static {
        try {
            // 反射技术获取unsafe值
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);

            // 获取到 value 属性偏移量(用于定于value属性在内存中的具体地址)
            valueOffset = unsafe.objectFieldOffset(LockDemo1.class.getDeclaredField("value"));

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void add() {
        // TODO xx00
        // i++;// JAVA 层面三个步骤:读取i的值 、i++、i的值写回主内存  
        // CAS + 循环 重试
        int current;
        do {
            // 操作耗时的话, 那么 线程就会占用大量的CPU执行时间
            //失败就从要修改的地址中重新获取值在操作(自旋锁)
            current = unsafe.getIntVolatile(this, valueOffset);
            //修改this当前对象的  valueOffset地址的值,先对比线程旧值和地址值是否一致,一致则修改成功返回true
        } while (!unsafe.compareAndSwapInt(this, valueOffset, current, current + 1));
        // 可能会失败
    }

    public static void main(String[] args) throws InterruptedException {
        LockDemo1 ld = new LockDemo1();

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    ld.add();
                }
            }).start();
        }
        Thread.sleep(2000L);
        System.out.println(ld.value);
    }
}

线程安全问题
线程安全问题

线程安全问题
线程安全问题
参考:cas自旋锁实现 及 ABA问题

相关标签: 高并发编程