乐趣区

关于java:这8种保证线程安全的技术你都知道吗

并发状况下如何保障数据安全,始终都是开发人员每天都要面对的问题,稍不留神就会呈现数据异样,造成不可挽回的后果。笔者依据本人的理论开发教训,总结了上面几种保障数据安全的技术手段:

  1. 无状态
  2. 不可变
  3. 平安的公布
  4. volatile
  5. synchronized
  6. lock
  7. cas
  8. threadlocal

一. 无状态

咱们都晓得只有多个线程拜访公共资源的时候,才可能呈现数据安全问题,那么如果咱们没有公共资源,是不是就没有这个问题呢?

public class NoStatusService {public void add(String status) {System.out.println("add status:" + status);
    }

    public void update(String status) {System.out.println("update status:" + status);
    }
}

二. 不可变

如果多个线程拜访公共资源是不可变的,也不会呈现数据的安全性问题。

public class NoChangeService {

    public static final String DEFAULT_NAME = "abc";

    public void add(String status) {System.out.println("add status:" + status);
    }
}

三. 平安的公布

如果类中有公共资源,然而没有对外开放拜访权限,即对外平安公布,也没有线程平安问题

public class SafePublishService {

    private String name;

    public String getName() {return name;}

    public void add(String status) {System.out.println("add status:" + status);
    }
}

四.volatile

如果有些公共资源只是一个开关,只要求可见性,不要求原子性,这样能够用 volidate 关键字定义来解决问题。

public class FlagService {

    public volatile boolean flag = false;


    public void change() {if (flag) {System.out.println("return");
            return;
        }
        flag = true;
        System.out.println("change");
    }
}

五.synchronized

应用 JDK 外部提供的同步机制,这也是应用比拟多的伎俩,分为:办法同步 和 代码块同步,咱们优先应用代码块同步,因为办法同步的范畴更大,更耗费性能。每个对象外部都又一把锁,只有抢答那把锁的线程,能力进入代码块里,代码块执行完之后,会主动开释锁。

public class SyncService {

    private int age = 1;

    public synchronized void add(int i) {
        age = age + i;
        System.out.println("age:" + age);
    }

    public void update(int i) {synchronized (this) {
            age = age + i;
            System.out.println("age:" + age);
        }
    }
}

六.lock

除了应用 synchronized 关键字实现同步性能之外,JDK 还提供了 lock 显示锁的形式。它蕴含:可重入锁、读写锁 等更多更弱小的性能,有个小问题就是须要手动开释锁,不过在编码时提供了更多的灵活性。

public class LockService {private ReentrantLock reentrantLock = new ReentrantLock();

    public int age = 1;


    public void add(int i) {
        try {reentrantLock.lock();
            age = age + i;
            System.out.println("age:" + age);
        } finally {reentrantLock.unlock();
        }
    }
}

七.cas

JDK 除了应用锁的机制解决多线程状况下数据安全问题之外,还提供了 cas 机制。这种机制是应用 CPU 中比拟和替换指令的原子性,JDK 外面是通过 Unsafe 类实现的。cas 须要四个值:旧数据、冀望数据、新数据 和 地址,比拟旧数据 和 冀望的数据如果一样的话,就把旧数据改成新数据,以后线程一直自旋,始终到胜利为止。不过可能会呈现 aba 问题,须要应用 AtomicStampedReference 减少版本号解决。其实,理论工作中很少间接应用 Unsafe 类的,个别用 atomic 包上面的类即可。

public class AtomicService {private AtomicInteger atomicInteger = new AtomicInteger();


    public int add(int i) {return atomicInteger.getAndAdd(i);
    }
}

八.threadlocal

除了下面几种解决思路之外,JDK 还提供了另外一种用空间换工夫的新思路:threadlocal。它的核心思想是:共享变量在每个线程都有一个正本,每个线程操作的都是本人的正本,对另外的线程没有影响。特地留神,应用 threadlocal 时,应用完之后,要记得调用 remove 办法,不然可能会呈现内存泄露问题。

public class ThreadLocalService {private ThreadLocal<Integer> threadLocal = new ThreadLocal<>();


    public void add(int i) {Integer integer = threadLocal.get();
        threadLocal.set(integer == null ? 0 : integer + i);
    }
}

总结

本文介绍了 8 种多线程状况下保障数据安全的技术手段,当然理论工作中可能会有其余。技术没有好坏之分,次要是看应用的场景,须要在不同的场景下应用不同的技术。

退出移动版