栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【面试:并发篇34:Unsafe】

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【面试:并发篇34:Unsafe】

【面试:并发篇34:Unsafe】 00.前言

如果有任何问题请指出,感谢。

01.介绍

Unsafe 对象提供了非常底层的,操作内存、线程的方法,Unsafe 对象不能直接调用,只能通过反射获得,因为Unsafe可以操控底层所以叫这个名字,并不是它线程不安全。

Unsafe源码

02.Unsafe CAS 操作
public class TestUnsafe {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafe.get(null);

        System.out.println(unsafe);

        // 1. 获取域的偏移地址
        long idOffset = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("id"));
        long nameOffset = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("name"));

        Teacher t = new Teacher();
        // 2. 执行 cas 操作
        unsafe.compareAndSwapInt(t, idOffset, 0, 1);
        unsafe.compareAndSwapObject(t, nameOffset, null, "张三");

        // 3. 验证
        System.out.println(t);
    }
}
@Data
class Teacher {
    volatile int id;
    volatile String name;
}

结果

sun.misc.Unsafe@4b1210ee
Teacher(id=1, name=张三)

解释
我们通过反射获取到Unsafe类,通过反射获取到成员变量的地址的偏移量 然后用Unsafe对象 unsafe直接cas改变Teacher对象t的值,最终打印发现确实改变了,我们通过更加底层的Unsafe 进行cas操作改变其他类 而不是通过原子更新器进行操作的。

03.通过Unsafe模拟原子整数类型 介绍

我们用Unsafe模拟的原子整数类型进行之前做过的取钱例子

代码

Account接口

interface Account {  
    // 获取余额  
    Integer getBalance();  
  
    // 取款  
    void withdraw(Integer amount);  
  
        static void demo(Account account) {  
        List ts = new ArrayList<>();  
        for (int i = 0; i < 1000; i++) {  
            ts.add(new Thread(() -> {  
                account.withdraw(10);  
            }));  
        }  
        long start = System.nanoTime();  
        ts.forEach(Thread::start);  
        ts.forEach(t -> {  
            try {  
                t.join();  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        });  
        long end = System.nanoTime();  
        System.out.println(account.getBalance()  
                + " cost: " + (end-start)/1000_000 + " ms");  
    }  
}

获取Unsafe对象的工具类

public class UnsafeAccessor {  
    private static final Unsafe unsafe;  
  
    static {  
        try {  
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");  
            theUnsafe.setAccessible(true);  
            unsafe = (Unsafe) theUnsafe.get(null);  
        } catch (NoSuchFieldException | IllegalAccessException e) {  
            throw new Error(e);  
        }  
    }  
  
    public static Unsafe getUnsafe() {  
        return unsafe;  
    }  
}

模拟取钱例子

@Slf4j(topic = "c.Test42")
public class Test42 {
    public static void main(String[] args) {
        Account.demo(new MyAtomicInteger(10000));
    }
}

class MyAtomicInteger implements Account {
    private volatile int value;
    private static final long valueOffset;
    private static final Unsafe UNSAFE;
    static {
        UNSAFE = UnsafeAccessor.getUnsafe();
        try {
            valueOffset = UNSAFE.objectFieldOffset(MyAtomicInteger.class.getDeclaredField("value"));
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public int getValue() {
        return value;
    }

    public void decrement(int amount) {
        while(true) {
            int prev = this.value;
            int next = prev - amount;
            if (UNSAFE.compareAndSwapInt(this, valueOffset, prev, next)) {
                break;
            }
        }
    }

    public MyAtomicInteger(int value) {
        this.value = value;
    }

    @Override
    public Integer getBalance() {
        return getValue();
    }

    @Override
    public void withdraw(Integer amount) {
        decrement(amount);
    }
}

结果

0 cost: 102 ms

解释
我们可以看出用Unsafe可以模拟原子整数类型 并且取钱例子没有线程安全问题,事实上大家可以看看原子类型的源码 全部都是用Unsafe实现的。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1031802.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号