zoukankan      html  css  js  c++  java
  • 自旋锁的原理实现

    import java.util.concurrent.atomic.AtomicReference;
    //boolean compareAndSet(V expect, V update)
    //如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值
    public class SpinLockDemo implements Runnable{
    private static int sum;
    private SpinLock spinLock;

    public SpinLockDemo(SpinLock spinLock){
    this.spinLock = spinLock;
    }
    @Override
    public void run() {
    this.spinLock.lock();
    sum ++;
    this.spinLock.unlock();
    }

    public static void main(String[] args) throws Exception{
    //首先看一个例子 AtomicReference用法
    Student st1 = new Student((long)8888);
    Student st2 = new Student((long)9999);
    AtomicReference ar = new AtomicReference(st1);
    //如果ar == st1 ,就更新新值为 st2
    Boolean flag = ar.compareAndSet(st1,st2);
    System.out.println("更新之后的值" + flag);
    Student st3 = (Student) ar.get();
    System.out.println("获取更新之后的值:" + st3.getId());
    /* 打印结果
    更新之后的值true
    获取更新之后的值:9999
    */
    System.out.println("--------------------------------");
    SpinLock lock = new SpinLock();
    for(int i=0;i<5;i++){
    SpinLockDemo spinLockDemo = new SpinLockDemo(lock);
    Thread thread = new Thread(spinLockDemo);
    thread.start();
    }
    Thread.currentThread().sleep(1000);
    System.out.println(sum);
    /*结论
    多次执行结果基本不一样原因是多个线程在未获取到释放之前会一直获取锁
    1. 自旋锁的缺陷 会造成死锁和CPU过高 比如如果不加sum<100,可能会造成死锁
    2. 自旋锁的实现基于共享变量。一个线程通过给共享变量设置一个值来获取锁,
    其他等待线程查询共享变量是否为0来确定锁是否可用,然后再等待循环中自旋直到锁可用为止
    个人感觉 对于锁时间短的可以用自旋锁,毕竟效率原高于互斥锁。而对于线程睡眠时间长的用互斥锁
    */
    }
    }

    //定义一个自选锁类
    class SpinLock{
    //AtomicReference java 13个原子操作的引用操作 线程安全
    //不足之处 当前线程对象获得当前数据后,准备修改为新值前,对象的值被其他线程修改了两次,经过
    //两次修改之后对象的值恢复为旧值,当前线程无法正确判断这个对象究竟是否被修改过
    AtomicReference<Thread> atomicReference = new AtomicReference<>();
    //初始化对象的话 预测原来的值就会不为空
    //AtomicReference atomicReference = new AtomicReference(Thread.currentThread());
    private int sum;
    private volatile int unsum;

    public void lock(){
    Thread curThread = Thread.currentThread();
    //lock将atomicReference设置为当前线程,并预测原来的值为空
    //如果有新线程调用lock,由于atomicReference的值不为空,新线程会一直循环获取,直到当前线程调用unlock
    Boolean flag = atomicReference.compareAndSet(null,curThread);
    System.out.println("当前线程比较之后的结果 " + flag);
    //第一次调用 当前值为空,所以flag为true
    while (!flag && sum < 100){
    sum ++;
    System.out.println("当前线程被加锁" + sum);

    }
    }
    //unlock将atomicReference设置为null,并预测值为当前线程
    public void unlock(){
    ++ unsum;
    System.out.println("当前线程被释放" + unsum);
    Thread curThread = Thread.currentThread();
    atomicReference.compareAndSet(curThread,null);
    }
    }

    class Student{
    volatile long id;

    public Student(Long id){
    this.id = id;
    }
    public long getId() {
    return id;
    }
    //编程技巧 对于未引用的对象属性,尽可能的减少
    /*public void setId(long id) {
    this.id = id;
    }*/

    @Override
    public String toString() {
    return "Student{" +
    "id=" + id +
    '}';
    }
    }
  • 相关阅读:
    windows2000/xp运行命令全集
    IP数据包的校验和算法C#版(原)
    做系统清理的批处理
    Combox用ValueMember 之后再添加一项
    安装部署基础——Windows Application
    文件编码
    Left/right join 和inner join 区别
    应用Url重写时CSS引用问题
    数据绑定控件单选框
    算法题:水杯倒水的问题
  • 原文地址:https://www.cnblogs.com/mutong1228/p/10543909.html
Copyright © 2011-2022 走看看