其他分享
首页 > 其他分享> > 解决并发问题的方法(有锁、无锁)

解决并发问题的方法(有锁、无锁)

作者:互联网

1 并发问题解决的方式

1.1 无锁的解决方式

1.1.1 局部变量

  public void test(){
    int i = 0;
    i++;
    System.out.println(i);
  }

1.1.2 不可变对象

    String s = "Hello"
    // “Hello”就是一个不可改变的对象,他就是一个固定的字符串。

1.1.3 ThreadLocal

1.1.4 CAS原子类

    // simple using of AtomicInteger
    private AtomicInteger counter = new AtomicInteger(0);
    public void atomicAdd(){
        counter.incrementAndGet();
    }
    // source code of Atomic 
    public class AtomicInteger extends Number implements java.io.Serializable{
        private static final long serialVsersionUID = ...;
        
        // setup to use Unsafe.compareAndSwapInt for updates
        private static final Unsafe unsafe = Unsafe.getUnsafe(); 
        // unsafe 提供硬件级别的原子操作,由于Java无法直接操控底层代码,为此Java需要使用native方法来拓展这部分功能,unsafe就是其中的一个操作入口。
        // unsafe提供了分配、释放内存,挂起、恢复程序,定位对象字段内存地址,修改对象字段值,CAS操作。
        private static final long valueOffset;

        static {
            try{
                valueOffset = unsafe.objectFieldOffset
                    (AtomicInteger.class.getDeclaredField(value));
            } catch(Exception ex){
                throw new Error(ex)
            }
        }
    }
    // source code of getAndAddInt
    // getAndAddInt method is a cas operate in unsafe class
    public final int getAndAddInt(Object var1, long var2, int var4){
        int var5;
        do{
            // use var5 to get the old value
            var5 = this.getIntVolatile(var1, var2);
            
            // compareAndSwapInt = cas
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }
    // a counter of interface which do not have concurrency problem.
    public static class AccessCounter{
        // count the times of the acccess to this interface
        AtomicInteger accessCount = new AtomicInteger(0);

        public void access(){
            accessCount.incrementAndGet();
            sout("reslut is: " + accountCount.get());
        }
    }

CAS操作实际模拟

  1. 两个线程同时对一个变量K(初始值0)加一。
  2. 线程A,线程B,获得K的旧值0.
  3. 线程A,把K加1以后,再次访问主存中的K,发现现在K的值(0)与自己记录的旧值(0)相等,所以生效,把自己操作的结果写入主存(k=0 --> k=1)
  4. 线程B,把K加1以后,再次访问主存中的K,发现现在的K值(1)与自己记录的旧值(0)不等,所以失效。再次记录主存中K的值,作为一个“新”的旧值。
  5. 线程B,把K加1以后,再次访问主存中的K,发现现在的K值(1)与自己记录的旧值(1)相等,所以生效,把自己的操作的结果写入主存(k=1 --> K=2)

1.2 有锁的解决方式

1.2.1 synchronized & reentrandLock

    public class Counter{
        private int i = 0;
        
        private ReentrantLock lock = new ReentrantLock();

        // lock by reentrantLock
        public void lockByReentrantLock(){
            lock.lock();
            try{
                add();
            } finally{
                lock.unlock();
            }
        }

        // lock by synchronized
        public synchronized void lockBySynchronized(){
            add();
        }

        private void add(){
            i++;
        }
    }

标签:无锁,CAS,void,private,并发,线程,AtomicInteger,有锁,public
来源: https://www.cnblogs.com/caiyiyang/p/14863326.html