seo发帖网站,百度seo快速见效方法,网络营销软件推广,wordpress修改404页面大家碰到了实现一个线程安全的计数器的需求改怎么做呢#xff1f;根据经验你应该知道我们要在多线程中实现共享变量的原子性和可见性问题#xff0c;于是锁成为一个不可避免的话题#xff0c;下文讨论的是与之对应的无锁CAS。为什么要无锁我们一想到在多线程下保证安全的方式…大家碰到了实现一个线程安全的计数器的需求改怎么做呢根据经验你应该知道我们要在多线程中实现共享变量的原子性和可见性问题于是锁成为一个不可避免的话题下文讨论的是与之对应的无锁CAS。为什么要无锁我们一想到在多线程下保证安全的方式肯定是锁不管从硬件、操作系统层面都或多或少在使用锁。锁有优缺点吗使用锁就需要获得锁、释放锁CPU需要通过上下文切换和调度管理来进行这个操作对于一个独占锁一个线程在持有锁后没有执行结束其他线程就必须等待等到前面的线程执行完毕CPU就会把锁拿出来给其他线程来抢了。锁的这种概念基于一种悲观机制它总是认为数据会被修改所以你在操作一部分代码块之前先加一把锁操作完成后再释放这样就安全了。什么是 CAS比较并交换(compare and swap,CAS),是原子操作的一种可用于在多线程编程中实现不被打断的数据交换操作从而避免多线程同时改写某一数据时由于执行顺序不确定性以及中断的不可预知性产生的数据不一致性问题。该操作通过将内存中的值与指定的数据进行比较当数值一样时将内存中的数据替换成新值。JAVA如何实现package com.concurrent.program;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.concurrent.atomic.AtomicInteger;public class Counter {private AtomicInteger atomicI new AtomicInteger(0);private int i 0;public static void main(String[] args) {final Counter cas new Counter();Listts new ArrayList(10);long start System.currentTimeMillis();for (int j0;j 100; j){Thread t new Thread(new Runnable() {Overridepublic void run() {for (int i0;i10000; i){cas.count();cas.safeCount();}}});ts.add(t);}for (Thread t : ts) {t.start();}//等待所有线程执行完成for (Thread t:ts){try {t.join();} catch (InterruptedException e){e.printStackTrace();}}System.out.println(cas.i);System.out.println(cas.atomicI.get());System.out.println(System.currentTimeMillis() - start);}/*** 使用CAS实现线程安全计数器*/private void safeCount(){for(;;){int i atomicI.get();boolean suc atomicI.compareAndSet(i, i);if (suc) {break;}}}/*** 非线程安全计数器*/private void count(){i;}}以上代码实现了一个基于CAS线程安全的计数器方法safeCount和一个非线程安全的计数器方法count读者可以自行运行运行结果如下非线程安全计数器: 971850使用CAS实现线程安全计数器: 1000000执行时间78msCAS存在的问题1.ABA问题。因为CAS需要在操作值的时候检查值有没有发生变化如果没有则更新。但是如果原来一个值是A变成了B又变成A那么使用CAS进行检查时会发现它的值没有发生变化但是实际发生了变化了。ABA解决问题的思路就是使用版本号。在变量前面追加版本号每次变量更新的时候把版本号加1那么A→B→A就会变成1A→2B→3A。从JAVA1.5开始JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。2.循环时间长开销大。CAS长时间不成功会给CPU带来非常大的执行开销。如果JVM能支持处理器提供的pause指令那么效率会有一定的提示。3.只能保证一个共享变量的原子操作。对多个共享变量操作时CAS可以把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i2ja合并成ij2a然后用CAS来操作ij。从JAVA1.5开始JDK的Atomic包里面提供了一个类AtomicReference类来保证引用对象之间的原子性就可以把多个变量放在一个对象里面来进行CAS操作。